From 4b46e22d48271d1a220133a925dc5009048eb577 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 30 Dec 2006 02:18:24 -0800 Subject: commit re-encoding: fix confusion between no and default conversion. Telling the git-log family not to do any character conversion is done with --encoding=none, which sets log_output_encoding to an empty string. However, logmsg_reencode() confused this with log_output_encoding and commit_encoding set to NULL. The latter means we should use the default encoding (i.e. utf-8). Signed-off-by: Junio C Hamano --- commit.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/commit.c b/commit.c index eb06afbbe0..e13b9cb6a3 100644 --- a/commit.c +++ b/commit.c @@ -633,6 +633,8 @@ static char *logmsg_reencode(const struct commit *commit) : git_commit_encoding); if (!output_encoding) + output_encoding = "utf-8"; + else if (!*output_encoding) return NULL; encoding = get_header(commit, "encoding"); if (!encoding || !strcmp(encoding, output_encoding)) { -- cgit v1.2.1 From 000792830b8ca96e6d973545192cba8d5df48279 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 30 Dec 2006 02:35:14 -0800 Subject: t3900: test log --encoding=none Signed-off-by: Junio C Hamano --- t/t3900-i18n-commit.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index 46fd47cb0f..6714b0dd6e 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -8,7 +8,7 @@ test_description='commit and log output encodings' . ./test-lib.sh compare_with () { - git-show -s "$1" | sed -e '1,/^$/d' -e 's/^ //' -e '$d' >current && + git-show -s $1 | sed -e '1,/^$/d' -e 's/^ //' -e '$d' >current && diff -u current "$2" } @@ -112,4 +112,11 @@ do done done +for H in ISO-8859-1 EUCJP ISO-2022-JP +do + test_expect_success "No conversion with $H" ' + compare_with "--encoding=none '$H'" ../t3900/'$H'.txt + ' +done + test_done -- cgit v1.2.1 From 5dc7bcc2453ce854dc1192cfffcc8aee1cc3b69d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 30 Dec 2006 02:22:38 -0800 Subject: Documentation: i18n commit log message notes. Signed-off-by: Junio C Hamano --- Documentation/git-commit-tree.txt | 5 ++++ Documentation/git-commit.txt | 5 ++++ Documentation/git-log.txt | 6 +++++ Documentation/git-show.txt | 5 ++++ Documentation/i18n.txt | 57 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+) create mode 100644 Documentation/i18n.txt diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt index 41d1a1c4b3..77ba96ed8a 100644 --- a/Documentation/git-commit-tree.txt +++ b/Documentation/git-commit-tree.txt @@ -81,6 +81,11 @@ Your parents must have hated you!:: Your sysadmin must hate you!:: The password(5) name field is longer than a giant static buffer. +Discussion +---------- + +include::i18n.txt[] + See Also -------- gitlink:git-write-tree[1] diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 0b74cd708e..a7adf24fa5 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -223,6 +223,11 @@ should be recorded as a single commit. In fact, the command refuses to run when given pathnames (but see `-i` option). +DISCUSSION +---------- + +include::i18n.txt[] + ENVIRONMENT VARIABLES --------------------- The command specified by either the VISUAL or EDITOR environment diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt index 79643ac928..c87133542a 100644 --- a/Documentation/git-log.txt +++ b/Documentation/git-log.txt @@ -63,6 +63,12 @@ git log -r --name-status release..test:: in the "release" branch, along with the list of paths each commit modifies. +Discussion +---------- + +include::i18n.txt[] + + Author ------ Written by Linus Torvalds diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt index 98dea6125d..160abb5b24 100644 --- a/Documentation/git-show.txt +++ b/Documentation/git-show.txt @@ -54,6 +54,11 @@ git show master:Makefile master:t/Makefile Concatenates the contents of said Makefiles in the head of the branch `master`. +Discussion +---------- + +include::i18n.txt[] + Author ------ Written by Linus Torvalds and diff --git a/Documentation/i18n.txt b/Documentation/i18n.txt new file mode 100644 index 0000000000..b4cbb3830e --- /dev/null +++ b/Documentation/i18n.txt @@ -0,0 +1,57 @@ +At the core level, git is character encoding agnostic. + + - The pathnames recorded in the index and in the tree objects + are treated as uninterpreted sequences of non-NUL bytes. + What readdir(2) returns are what are recorded and compared + with the data git keeps track of, which in turn are expected + to be what lstat(2) and creat(2) accepts. There is no such + thing as pathname encoding translation. + + - The contents of the blob objects are uninterpreted sequence + of bytes. There is no encoding translation at the core + level. + + - The commit log messages are uninterpreted sequence of non-NUL + bytes. + +Although we encourage that the commit log messages are encoded +in UTF-8, both the core and git Porcelain are designed not to +force UTF-8 on projects. If all participants of a particular +project find it more convenient to use legacy encodings, git +does not forbid it. However, there are a few things to keep in +mind. + +. `git-commit-tree` (hence, `git-commit` which uses it) issues + an warning if the commit log message given to it does not look + like a valid UTF-8 string, unless you explicitly say your + project uses a legacy encoding. The way to say this is to + have core.commitencoding in `.git/config` file, like this: ++ +------------ +[core] + commitencoding = ISO-8859-1 +------------ ++ +Commit objects created with the above setting record the value +of `core.commitencoding` in its `encoding` header. This is to +help other people who look at them later. Lack of this header +implies that the commit log message is encoded in UTF-8. + +. `git-log`, `git-show` and friends looks at the `encoding` + header of a commit object, and tries to re-code the log + message into UTF-8 unless otherwise specified. You can + specify the desired output encoding with + `core.logoutputencoding` in `.git/config` file, like this: ++ +------------ +[core] + logoutputencoding = ISO-8859-1 +------------ ++ +If you do not have this configuration variable, the value of +`core.commitencoding` is used instead. + +Note that we deliberately chose not to re-code the commit log +message when a commit is made to force UTF-8 at the commit +object level, because re-coding to UTF-8 is not necessarily a +reversible operation. -- cgit v1.2.1 From 99e09cce8d0eace48209483b07e2a9d99542bd04 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 30 Dec 2006 02:21:48 -0800 Subject: Documentation: minor rewording for git-log and git-show pages. Signed-off-by: Junio C Hamano --- Documentation/git-log.txt | 4 +++- Documentation/git-show.txt | 10 ++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt index c87133542a..e9f746bbd4 100644 --- a/Documentation/git-log.txt +++ b/Documentation/git-log.txt @@ -31,7 +31,9 @@ include::pretty-formats.txt[] Limits the number of commits to show. ..:: - Show only commits between the named two commits. + Show only commits between the named two commits. When + either or is omitted, it defaults to + `HEAD`, i.e. the tip of the current branch. -p:: Show the change the commit introduces in a patch form. diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt index 160abb5b24..c210b9af6b 100644 --- a/Documentation/git-show.txt +++ b/Documentation/git-show.txt @@ -30,8 +30,8 @@ This manual page describes only the most frequently used options. OPTIONS ------- -:: - ID of the commit to show. +:: + The name of the object to show. include::pretty-formats.txt[] @@ -40,7 +40,8 @@ EXAMPLES -------- git show v1.0.0:: - Shows the tag `v1.0.0`. + Shows the tag `v1.0.0`, along with the object the tags + points at. git show v1.0.0^{tree}:: Shows the tree pointed to by the tag `v1.0.0`. @@ -62,7 +63,8 @@ include::i18n.txt[] Author ------ Written by Linus Torvalds and -Junio C Hamano +Junio C Hamano . Significantly enhanced by +Johannes Schindelin . Documentation -- cgit v1.2.1 From 7cbcf4d5579bdc5d9f8a4bf3f37d3390fc6e2572 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 30 Dec 2006 11:59:08 -0800 Subject: Move commit reencoding parameter parsing to revision.c This way, git-rev-list and git-diff-tree with --pretty can use it. Signed-off-by: Junio C Hamano --- Documentation/git-rev-list.txt | 1 + Documentation/pretty-formats.txt | 7 +++++++ revision.c | 8 ++++++++ 3 files changed, 16 insertions(+) diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index 9e0dcf8d3f..86c94e7dfd 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -21,6 +21,7 @@ SYNOPSIS [ \--stdin ] [ \--topo-order ] [ \--parents ] + [ \--encoding[=] ] [ \--(author|committer|grep)= ] [ [\--objects | \--objects-edge] [ \--unpacked ] ] [ \--pretty | \--header ] diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index 996f628903..fb0b0b9582 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -76,3 +76,10 @@ displayed in full, regardless of whether --abbrev or --no-abbrev are used, and 'parents' information show the true parent commits, without taking grafts nor history simplification into account. + +--encoding[=]:: + The commit objects record the encoding used for the log message + in their encoding header; this option can be used to tell the + command to re-code the commit log message in the encoding + preferred by the user. For non plumbing commands this + defaults to UTF-8. diff --git a/revision.c b/revision.c index af9f87418c..6e4ec46302 100644 --- a/revision.c +++ b/revision.c @@ -1039,6 +1039,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch all_match = 1; continue; } + if (!strncmp(arg, "--encoding=", 11)) { + arg += 11; + if (strcmp(arg, "none")) + git_log_output_encoding = strdup(arg); + else + git_log_output_encoding = ""; + continue; + } opts = diff_opt_parse(&revs->diffopt, argv+i, argc-i); if (opts > 0) { -- cgit v1.2.1 From 677cfed56ac530878b746ee4cca3ada8af384a81 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 30 Dec 2006 12:20:43 -0800 Subject: commit-tree: cope with different ways "utf-8" can be spelled. People can spell config.commitencoding differently from what we internally have ("utf-8") to mean UTF-8. Try to accept them and treat them equally. Signed-off-by: Junio C Hamano --- builtin-commit-tree.c | 3 +-- utf8.c | 9 +++++++++ utf8.h | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c index 146aaffd28..0651e5927e 100644 --- a/builtin-commit-tree.c +++ b/builtin-commit-tree.c @@ -119,8 +119,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) } /* Not having i18n.commitencoding is the same as having utf-8 */ - encoding_is_utf8 = (!git_commit_encoding || - !strcmp(git_commit_encoding, "utf-8")); + encoding_is_utf8 = is_encoding_utf8(git_commit_encoding); init_buffer(&buffer, &size); add_buffer(&buffer, &size, "tree %s\n", sha1_to_hex(tree_sha1)); diff --git a/utf8.c b/utf8.c index 1eedd8b61a..7c80eeccb4 100644 --- a/utf8.c +++ b/utf8.c @@ -277,6 +277,15 @@ void print_wrapped_text(const char *text, int indent, int indent2, int width) } } +int is_encoding_utf8(const char *name) +{ + if (!name) + return 1; + if (!strcasecmp(name, "utf-8") || !strcasecmp(name, "utf8")) + return 1; + return 0; +} + /* * Given a buffer and its encoding, return it re-encoded * with iconv. If the conversion fails, returns NULL. diff --git a/utf8.h b/utf8.h index cae2a8e665..a07c5a88af 100644 --- a/utf8.h +++ b/utf8.h @@ -3,6 +3,8 @@ int utf8_width(const char **start); int is_utf8(const char *text); +int is_encoding_utf8(const char *name); + void print_wrapped_text(const char *text, int indent, int indent2, int len); #ifndef NO_ICONV -- cgit v1.2.1 From 53af9816bcb1d441fef76c3adaf0c4cb858768ac Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 30 Dec 2006 15:49:32 -0800 Subject: i18n: drop "encoding" header in the output after re-coding. After re-coding the commit message into the encoding the user specified (either with core.logoutputencidng or --encoding option), this drops the "encoding" header altogether. The output is after re-coding as the user asked (either with the config or --encoding= option), and the extra header becomes redundant information. Signed-off-by: Junio C Hamano --- commit.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/commit.c b/commit.c index e13b9cb6a3..afdf27eece 100644 --- a/commit.c +++ b/commit.c @@ -624,6 +624,48 @@ static char *get_header(const struct commit *commit, const char *key) } } +static char *replace_encoding_header(char *buf, char *encoding) +{ + char *encoding_header = strstr(buf, "\nencoding "); + char *end_of_encoding_header; + int encoding_header_pos; + int encoding_header_len; + int new_len; + int need_len; + int buflen = strlen(buf) + 1; + + if (!encoding_header) + return buf; /* should not happen but be defensive */ + encoding_header++; + end_of_encoding_header = strchr(encoding_header, '\n'); + if (!end_of_encoding_header) + return buf; /* should not happen but be defensive */ + end_of_encoding_header++; + + encoding_header_len = end_of_encoding_header - encoding_header; + encoding_header_pos = encoding_header - buf; + + if (is_encoding_utf8(encoding)) { + /* we have re-coded to UTF-8; drop the header */ + memmove(encoding_header, end_of_encoding_header, + buflen - (encoding_header_pos + encoding_header_len)); + return buf; + } + new_len = strlen(encoding); + need_len = new_len + strlen("encoding \n"); + if (encoding_header_len < need_len) { + buf = xrealloc(buf, buflen + (need_len - encoding_header_len)); + encoding_header = buf + encoding_header_pos; + end_of_encoding_header = encoding_header + encoding_header_len; + } + memmove(end_of_encoding_header + (need_len - encoding_header_len), + end_of_encoding_header, + buflen - (encoding_header_pos + encoding_header_len)); + memcpy(encoding_header + 9, encoding, strlen(encoding)); + encoding_header[9 + new_len] = '\n'; + return buf; +} + static char *logmsg_reencode(const struct commit *commit) { char *encoding; @@ -642,6 +684,9 @@ static char *logmsg_reencode(const struct commit *commit) return NULL; } out = reencode_string(commit->buffer, output_encoding, encoding); + if (out) + out = replace_encoding_header(out, output_encoding); + free(encoding); if (!out) return NULL; -- cgit v1.2.1 From 22b6abcd0872c50f4bff47e96819a86db4bb6e61 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 31 Dec 2006 02:07:41 +0100 Subject: Fix yet another subtle xdl_merge() bug In very obscure cases, a merge can hit an unexpected code path (where the original code went as far as saying that this was a bug). This failing merge was noticed by Alexandre Juillard. The problem is that the original file contains something like this: -- snip -- two non-empty lines before two empty lines after two empty lines -- snap -- and this snippet is reduced to _one_ empty line in _both_ new files. However, it is ambiguous as to which hunk takes the empty line: the first or the second one? Indeed in Alexandre's example files, the xdiff algorithm attributes the empty line to the first hunk in one case, and to the second hunk in the other case. (Trimming down the example files _changes_ that behaviour!) Thus, the call to xdl_merge_cmp_lines() has no chance to realize that the change is actually identical in both new files. Therefore, xdl_refine_conflicts() finds an empty diff script, which was not expected there, because (the original author of xdl_merge() thought) xdl_merge_cmp_lines() would catch that case earlier. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- xdiff/xmerge.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c index 294450b899..b83b3348cc 100644 --- a/xdiff/xmerge.c +++ b/xdiff/xmerge.c @@ -166,6 +166,8 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1, size += xdl_recs_copy(xe2, m->i2 - m->i1 + i1, m->i1 + m->chg2 - i1, 0, dest ? dest + size : NULL); + else + continue; i1 = m->i1 + m->chg1; } size += xdl_recs_copy(xe1, i1, xe1->xdf2.nrec - i1, 0, @@ -213,9 +215,10 @@ static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m, return -1; } if (!xscr) { - /* If this happens, it's a bug. */ + /* If this happens, the changes are identical. */ xdl_free_env(&xe); - return -2; + m->mode = 4; + continue; } x = xscr; m->i1 = xscr->i1 + i1; -- cgit v1.2.1 From 400e74df98e0808ccf233025fe700a316f65854c Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 30 Dec 2006 20:03:51 -0500 Subject: Fix formatting for urls section of fetch, pull, and push manpages The line: [remote ""] was getting swallowed up by asciidoc, causing a critical line in the explanation for how to store the .git/remotes information in .git/config to go missing from the git-fetch, git-pull, and git-push manpages. Put all of the examples into delimited blocks to fix this problem and to make them look nicer. Signed-off-by: "Theodore Ts'o" Signed-off-by: Junio C Hamano --- Documentation/urls.txt | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/Documentation/urls.txt b/Documentation/urls.txt index 670827c323..870c95073b 100644 --- a/Documentation/urls.txt +++ b/Documentation/urls.txt @@ -40,9 +40,11 @@ In addition to the above, as a short-hand, the name of a file in `$GIT_DIR/remotes` directory can be given; the named file should be in the following format: - URL: one of the above URL format - Push: - Pull: +------------ +URL: one of the above URL format +Push: +Pull: +------------ Then such a short-hand is specified in place of without parameters on the command @@ -54,10 +56,12 @@ be specified for additional branch mappings. Or, equivalently, in the `$GIT_DIR/config` (note the use of `fetch` instead of `Pull:`): +------------ [remote ""] url = push = fetch = +------------ The name of a file in `$GIT_DIR/branches` directory can be specified as an older notation short-hand; the named @@ -68,10 +72,15 @@ name of remote head (URL fragment notation). without the fragment is equivalent to have this in the corresponding file in the `$GIT_DIR/remotes/` directory. - URL: - Pull: refs/heads/master: +------------ +URL: +Pull: refs/heads/master: +------------ + while having `#` is equivalent to - URL: - Pull: refs/heads/: +------------ +URL: +Pull: refs/heads/: +------------ -- cgit v1.2.1 From c869753ebbb00e188da5ab308d42cc738335f0ab Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 30 Dec 2006 23:53:55 -0500 Subject: Force core.filemode to false on Cygwin. Many users have noticed that core.filemode doesn't appear to be automatically set right on Cygwin when using a repository stored on NTFS. The issue is that Cygwin and NTFS correctly supports the executable mode bit, and Git properly detected that, but most native Windows applications tend to create files such that Cygwin sees the executable bit set when it probably shouldn't be. This is especially bad if the user's favorite editor deletes the file then recreates it whenever they save (vs. just overwriting) as now a file that was created with mode 0644 by checkout-index appears to have mode 0755. So we introduce NO_TRUSTABLE_FILEMODE, settable at compile time. Setting this option forces core.filemode to false, even if the detection code would have returned true. This option should be enabled by default on Cygwin. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- Makefile | 7 +++++++ builtin-init-db.c | 15 +++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 93dc4948d3..fa1a02289c 100644 --- a/Makefile +++ b/Makefile @@ -72,6 +72,9 @@ all: # Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is # generally faster on your platform than accessing the working directory. # +# Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support +# the executable mode bit, but doesn't really do so. +# # Define NO_IPV6 if you lack IPv6 support and getaddrinfo(). # # Define NO_SOCKADDR_STORAGE if your platform does not have struct @@ -361,6 +364,7 @@ ifeq ($(uname_O),Cygwin) NEEDS_LIBICONV = YesPlease NO_C99_FORMAT = YesPlease NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes + NO_TRUSTABLE_FILEMODE = UnfortunatelyYes # There are conflicting reports about this. # On some boxes NO_MMAP is needed, and not so elsewhere. # Try commenting this out if you suspect MMAP is more efficient @@ -521,6 +525,9 @@ endif ifdef NO_FAST_WORKING_DIRECTORY BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY endif +ifdef NO_TRUSTABLE_FILEMODE + BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE +endif ifdef NO_IPV6 BASIC_CFLAGS += -DNO_IPV6 endif diff --git a/builtin-init-db.c b/builtin-init-db.c index 01f366ad0b..97fd82ff06 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -10,6 +10,12 @@ #define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/" #endif +#ifdef NO_TRUSTABLE_FILEMODE +#define TEST_FILEMODE 0 +#else +#define TEST_FILEMODE 1 +#endif + static void safe_create_dir(const char *dir, int share) { if (mkdir(dir, 0777) < 0) { @@ -175,6 +181,7 @@ static int create_default_files(const char *git_dir, const char *template_path) struct stat st1; char repo_version_string[10]; int reinit; + int filemode; if (len > sizeof(path)-50) die("insane git directory %s", git_dir); @@ -236,14 +243,14 @@ static int create_default_files(const char *git_dir, const char *template_path) strcpy(path + len, "config"); /* Check filemode trustability */ - if (!lstat(path, &st1)) { + filemode = TEST_FILEMODE; + if (TEST_FILEMODE && !lstat(path, &st1)) { struct stat st2; - int filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) && + filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) && !lstat(path, &st2) && st1.st_mode != st2.st_mode); - git_config_set("core.filemode", - filemode ? "true" : "false"); } + git_config_set("core.filemode", filemode ? "true" : "false"); /* Enable logAllRefUpdates if a working tree is attached */ if (!is_bare_git_dir(git_dir)) -- cgit v1.2.1 From ef5ddb2fe0cdb3bd09acb7229512b6ae9193423f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 30 Dec 2006 23:28:53 -0500 Subject: Use PATH_MAX constant for --bare. For easier portability we prefer PATH_MAX over seemingly random constants like 1024. Make it so. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- git.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git.c b/git.c index 50ebd869ad..ec897dc88c 100644 --- a/git.c +++ b/git.c @@ -69,8 +69,8 @@ static int handle_options(const char*** argv, int* argc) } else if (!strncmp(cmd, "--git-dir=", 10)) { setenv("GIT_DIR", cmd + 10, 1); } else if (!strcmp(cmd, "--bare")) { - static char git_dir[1024]; - setenv("GIT_DIR", getcwd(git_dir, 1024), 1); + static char git_dir[PATH_MAX+1]; + setenv("GIT_DIR", getcwd(git_dir, sizeof(git_dir)), 1); } else { fprintf(stderr, "Unknown option: %s\n", cmd); usage(git_usage_string); -- cgit v1.2.1 From 45b097947d6297a4b3f1016b05c66cdc15b411c2 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 30 Dec 2006 23:29:11 -0500 Subject: Replace "GIT_DIR" with GIT_DIR_ENVIRONMENT. We tend to use the nice constant GIT_DIR_ENVIRONMENT when we are referring to the "GIT_DIR" constant, but git.c didn't do so. Now it does. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- git.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/git.c b/git.c index ec897dc88c..c82ca458e4 100644 --- a/git.c +++ b/git.c @@ -63,14 +63,14 @@ static int handle_options(const char*** argv, int* argc) fprintf(stderr, "No directory given for --git-dir.\n" ); usage(git_usage_string); } - setenv("GIT_DIR", (*argv)[1], 1); + setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1); (*argv)++; (*argc)--; } else if (!strncmp(cmd, "--git-dir=", 10)) { - setenv("GIT_DIR", cmd + 10, 1); + setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1); } else if (!strcmp(cmd, "--bare")) { static char git_dir[PATH_MAX+1]; - setenv("GIT_DIR", getcwd(git_dir, sizeof(git_dir)), 1); + setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 1); } else { fprintf(stderr, "Unknown option: %s\n", cmd); usage(git_usage_string); -- cgit v1.2.1 From ad1a382fbb3ecb1bb017854a470816c815cc46c9 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 30 Dec 2006 23:30:19 -0500 Subject: Automatically detect a bare git repository. Many users find it unfriendly that they can create a bare git repository easily with `git clone --bare` but are then unable to run simple commands like `git log` once they cd into that newly created bare repository. This occurs because we do not check to see if the current working directory is a git repository. Instead of failing out with "fatal: Not a git repository" we should try to automatically detect if the current working directory is a bare repository and use that for GIT_DIR, and fail out only if that doesn't appear to be true. We test the current working directory only after we have tried searching up the directory tree. This is to retain backwards compatibility with our previous behavior on the off chance that a user has a 'refs' and 'objects' subdirectories and a 'HEAD' file that looks like a symref, all stored within a repository's associated working directory. This change also consolidates the validation logic between the case of GIT_DIR being supplied and GIT_DIR not being supplied, cleaning up the code. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- setup.c | 73 +++++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/setup.c b/setup.c index 2afdba414a..2ae57f7c94 100644 --- a/setup.c +++ b/setup.c @@ -131,28 +131,46 @@ const char **get_pathspec(const char *prefix, const char **pathspec) } /* - * Test if it looks like we're at the top level git directory. + * Test if it looks like we're at a git directory. * We want to see: * - * - either a .git/objects/ directory _or_ the proper + * - either a objects/ directory _or_ the proper * GIT_OBJECT_DIRECTORY environment variable - * - a refs/ directory under ".git" + * - a refs/ directory * - either a HEAD symlink or a HEAD file that is formatted as * a proper "ref:". */ -static int is_toplevel_directory(void) +static int is_git_directory(const char *suspect) { - if (access(".git/refs/", X_OK) || - access(getenv(DB_ENVIRONMENT) ? - getenv(DB_ENVIRONMENT) : ".git/objects/", X_OK) || - validate_symref(".git/HEAD")) + char path[PATH_MAX]; + size_t len = strlen(suspect); + + strcpy(path, suspect); + if (getenv(DB_ENVIRONMENT)) { + if (access(getenv(DB_ENVIRONMENT), X_OK)) + return 0; + } + else { + strcpy(path + len, "/objects"); + if (access(path, X_OK)) + return 0; + } + + strcpy(path + len, "/refs"); + if (access(path, X_OK)) return 0; + + strcpy(path + len, "/HEAD"); + if (validate_symref(path)) + return 0; + return 1; } const char *setup_git_directory_gently(int *nongit_ok) { static char cwd[PATH_MAX+1]; + const char *gitdirenv; int len, offset; /* @@ -160,36 +178,17 @@ const char *setup_git_directory_gently(int *nongit_ok) * to do any discovery, but we still do repository * validation. */ - if (getenv(GIT_DIR_ENVIRONMENT)) { - char path[PATH_MAX]; - int len = strlen(getenv(GIT_DIR_ENVIRONMENT)); - if (sizeof(path) - 40 < len) + gitdirenv = getenv(GIT_DIR_ENVIRONMENT); + if (gitdirenv) { + if (PATH_MAX - 40 < strlen(gitdirenv)) die("'$%s' too big", GIT_DIR_ENVIRONMENT); - memcpy(path, getenv(GIT_DIR_ENVIRONMENT), len); - - strcpy(path + len, "/refs"); - if (access(path, X_OK)) - goto bad_dir_environ; - strcpy(path + len, "/HEAD"); - if (validate_symref(path)) - goto bad_dir_environ; - if (getenv(DB_ENVIRONMENT)) { - if (access(getenv(DB_ENVIRONMENT), X_OK)) - goto bad_dir_environ; - } - else { - strcpy(path + len, "/objects"); - if (access(path, X_OK)) - goto bad_dir_environ; - } - return NULL; - bad_dir_environ: + if (is_git_directory(gitdirenv)) + return NULL; if (nongit_ok) { *nongit_ok = 1; return NULL; } - path[len] = 0; - die("Not a git repository: '%s'", path); + die("Not a git repository: '%s'", gitdirenv); } if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/') @@ -197,11 +196,17 @@ const char *setup_git_directory_gently(int *nongit_ok) offset = len = strlen(cwd); for (;;) { - if (is_toplevel_directory()) + if (is_git_directory(".git")) break; chdir(".."); do { if (!offset) { + if (is_git_directory(cwd)) { + if (chdir(cwd)) + die("Cannot come back to cwd"); + setenv(GIT_DIR_ENVIRONMENT, cwd, 1); + return NULL; + } if (nongit_ok) { if (chdir(cwd)) die("Cannot come back to cwd"); -- cgit v1.2.1 From 9b0b50936ec76ad8e582d18d5bf54bc81c685e9b Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 30 Dec 2006 21:55:15 -0500 Subject: Remove unnecessary argc parameter from run_command_v. The argc parameter is never used by the run_command_v family of functions. Instead they require that the passed argv[] be NULL terminated so they can rely on the operating system's execvp function to correctly pass the arguments to the new process. Making the caller pass the argc is just confusing, as the caller could be mislead into believing that the argc might take precendece over the argv, or that the argv does not need to be NULL terminated. So goodbye argc. Don't come back. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-push.c | 2 +- receive-pack.c | 4 ++-- run-command.c | 8 ++++---- run-command.h | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/builtin-push.c b/builtin-push.c index b7412e8293..7a3d2bb064 100644 --- a/builtin-push.c +++ b/builtin-push.c @@ -275,7 +275,7 @@ static int do_push(const char *repo) argv[dest_argc] = NULL; if (verbose) fprintf(stderr, "Pushing to %s\n", dest); - err = run_command_v(argc, argv); + err = run_command_v(argv); if (!err) continue; switch (err) { diff --git a/receive-pack.c b/receive-pack.c index 59b682c03a..2b0ba638af 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -187,7 +187,7 @@ static void run_update_post_hook(struct command *cmd) argc++; } argv[argc] = NULL; - run_command_v_opt(argc, argv, RUN_COMMAND_NO_STDIO); + run_command_v_opt(argv, RUN_COMMAND_NO_STDIO); } /* @@ -283,7 +283,7 @@ static const char *unpack(void) unpacker[0] = "unpack-objects"; unpacker[1] = hdr_arg; unpacker[2] = NULL; - code = run_command_v_opt(1, unpacker, RUN_GIT_CMD); + code = run_command_v_opt(unpacker, RUN_GIT_CMD); switch (code) { case 0: return NULL; diff --git a/run-command.c b/run-command.c index 492ad3e64c..d0330c3793 100644 --- a/run-command.c +++ b/run-command.c @@ -2,7 +2,7 @@ #include "run-command.h" #include "exec_cmd.h" -int run_command_v_opt(int argc, const char **argv, int flags) +int run_command_v_opt(const char **argv, int flags) { pid_t pid = fork(); @@ -46,9 +46,9 @@ int run_command_v_opt(int argc, const char **argv, int flags) } } -int run_command_v(int argc, const char **argv) +int run_command_v(const char **argv) { - return run_command_v_opt(argc, argv, 0); + return run_command_v_opt(argv, 0); } int run_command(const char *cmd, ...) @@ -69,5 +69,5 @@ int run_command(const char *cmd, ...) va_end(param); if (MAX_RUN_COMMAND_ARGS <= argc) return error("too many args to run %s", cmd); - return run_command_v_opt(argc, argv, 0); + return run_command_v_opt(argv, 0); } diff --git a/run-command.h b/run-command.h index 70b477a748..82a0861f23 100644 --- a/run-command.h +++ b/run-command.h @@ -13,8 +13,8 @@ enum { #define RUN_COMMAND_NO_STDIO 1 #define RUN_GIT_CMD 2 /*If this is to be git sub-command */ -int run_command_v_opt(int argc, const char **argv, int opt); -int run_command_v(int argc, const char **argv); +int run_command_v_opt(const char **argv, int opt); +int run_command_v(const char **argv); int run_command(const char *cmd, ...); #endif -- cgit v1.2.1 From cd83c74cb3161a19b5efd33f40cfe378c2f64ddb Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 30 Dec 2006 21:55:19 -0500 Subject: Redirect update hook stdout to stderr. If an update hook outputs to stdout then that output will be sent back over the wire to the push client as though it were part of the git protocol. This tends to cause protocol errors on the client end of the connection, as the hook output is not expected in that context. Most hook developers work around this by making sure their hook outputs everything to stderr. But hooks shouldn't need to perform such special behavior. Instead we can just dup stderr to stdout prior to invoking the update hook. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- receive-pack.c | 3 ++- run-command.c | 32 ++++++++++++++++++++++++++------ run-command.h | 2 ++ 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/receive-pack.c b/receive-pack.c index 2b0ba638af..48e49465ba 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -73,7 +73,8 @@ static int run_update_hook(const char *refname, if (access(update_hook, X_OK) < 0) return 0; - code = run_command(update_hook, refname, old_hex, new_hex, NULL); + code = run_command_opt(RUN_COMMAND_STDOUT_TO_STDERR, + update_hook, refname, old_hex, new_hex, NULL); switch (code) { case 0: return 0; diff --git a/run-command.c b/run-command.c index d0330c3793..7e4ca43c62 100644 --- a/run-command.c +++ b/run-command.c @@ -14,7 +14,8 @@ int run_command_v_opt(const char **argv, int flags) dup2(fd, 0); dup2(fd, 1); close(fd); - } + } else if (flags & RUN_COMMAND_STDOUT_TO_STDERR) + dup2(2, 1); if (flags & RUN_GIT_CMD) { execv_git_cmd(argv); } else { @@ -51,14 +52,12 @@ int run_command_v(const char **argv) return run_command_v_opt(argv, 0); } -int run_command(const char *cmd, ...) +static int run_command_va_opt(int opt, const char *cmd, va_list param) { int argc; const char *argv[MAX_RUN_COMMAND_ARGS]; const char *arg; - va_list param; - va_start(param, cmd); argv[0] = (char*) cmd; argc = 1; while (argc < MAX_RUN_COMMAND_ARGS) { @@ -66,8 +65,29 @@ int run_command(const char *cmd, ...) if (!arg) break; } - va_end(param); if (MAX_RUN_COMMAND_ARGS <= argc) return error("too many args to run %s", cmd); - return run_command_v_opt(argv, 0); + return run_command_v_opt(argv, opt); +} + +int run_command_opt(int opt, const char *cmd, ...) +{ + va_list params; + int r; + + va_start(params, cmd); + r = run_command_va_opt(opt, cmd, params); + va_end(params); + return r; +} + +int run_command(const char *cmd, ...) +{ + va_list params; + int r; + + va_start(params, cmd); + r = run_command_va_opt(0, cmd, params); + va_end(params); + return r; } diff --git a/run-command.h b/run-command.h index 82a0861f23..8156eac31b 100644 --- a/run-command.h +++ b/run-command.h @@ -13,8 +13,10 @@ enum { #define RUN_COMMAND_NO_STDIO 1 #define RUN_GIT_CMD 2 /*If this is to be git sub-command */ +#define RUN_COMMAND_STDOUT_TO_STDERR 4 int run_command_v_opt(const char **argv, int opt); int run_command_v(const char **argv); +int run_command_opt(int opt, const char *cmd, ...); int run_command(const char *cmd, ...); #endif -- cgit v1.2.1 From 95d3c4f546c664c3571dd4a93f11ae2f54e55e6e Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 30 Dec 2006 21:55:22 -0500 Subject: Use /dev/null for update hook stdin. Currently the update hook invoked by receive-pack has its stdin connected to the pushing client. The hook shouldn't attempt to read from this stream, and doing so may consume data that was meant for receive-pack. Instead we should give the update hook /dev/null as its stdin, ensuring that it always receives EOF and doesn't disrupt the protocol if it attempts to read any data. The post-update hook is similar, as it gets invoked with /dev/null on stdin to prevent the hook from reading data from the client. Previously we had invoked it with stdout also connected to /dev/null, throwing away anything on stdout, to prevent client protocol errors. Instead we should redirect stdout to stderr, like we do with the update hook. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- receive-pack.c | 6 ++++-- run-command.c | 6 +++--- run-command.h | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/receive-pack.c b/receive-pack.c index 48e49465ba..c176d8fd00 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -73,7 +73,8 @@ static int run_update_hook(const char *refname, if (access(update_hook, X_OK) < 0) return 0; - code = run_command_opt(RUN_COMMAND_STDOUT_TO_STDERR, + code = run_command_opt(RUN_COMMAND_NO_STDIN + | RUN_COMMAND_STDOUT_TO_STDERR, update_hook, refname, old_hex, new_hex, NULL); switch (code) { case 0: @@ -188,7 +189,8 @@ static void run_update_post_hook(struct command *cmd) argc++; } argv[argc] = NULL; - run_command_v_opt(argv, RUN_COMMAND_NO_STDIO); + run_command_v_opt(argv, RUN_COMMAND_NO_STDIN + | RUN_COMMAND_STDOUT_TO_STDERR); } /* diff --git a/run-command.c b/run-command.c index 7e4ca43c62..cfbad74d14 100644 --- a/run-command.c +++ b/run-command.c @@ -9,12 +9,12 @@ int run_command_v_opt(const char **argv, int flags) if (pid < 0) return -ERR_RUN_COMMAND_FORK; if (!pid) { - if (flags & RUN_COMMAND_NO_STDIO) { + if (flags & RUN_COMMAND_NO_STDIN) { int fd = open("/dev/null", O_RDWR); dup2(fd, 0); - dup2(fd, 1); close(fd); - } else if (flags & RUN_COMMAND_STDOUT_TO_STDERR) + } + if (flags & RUN_COMMAND_STDOUT_TO_STDERR) dup2(2, 1); if (flags & RUN_GIT_CMD) { execv_git_cmd(argv); diff --git a/run-command.h b/run-command.h index 8156eac31b..59c4476ced 100644 --- a/run-command.h +++ b/run-command.h @@ -11,7 +11,7 @@ enum { ERR_RUN_COMMAND_WAITPID_NOEXIT, }; -#define RUN_COMMAND_NO_STDIO 1 +#define RUN_COMMAND_NO_STDIN 1 #define RUN_GIT_CMD 2 /*If this is to be git sub-command */ #define RUN_COMMAND_STDOUT_TO_STDERR 4 int run_command_v_opt(const char **argv, int opt); -- cgit v1.2.1 From d77a64d353cea0f72655b86dd04bcf9f86cbbea6 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 30 Dec 2006 22:13:05 -0500 Subject: Teach Git how to parse standard power of 2 suffixes. Sometimes its necessary to supply a value as a power of two in a configuration parameter. In this case the user may want to use the standard suffixes such as K, M, or G to indicate that the numerical value should be multiplied by a constant base before being used. Shell scripts/etc. can also benefit from this automatic option parsing with `git repo-config --int`. [jc: with a couple of test and a slight input tightening] Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- Documentation/git-repo-config.txt | 5 ++++- config.c | 6 ++++++ t/t1300-repo-config.sh | 10 ++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Documentation/git-repo-config.txt b/Documentation/git-repo-config.txt index b379ec5075..c55a8ba0dc 100644 --- a/Documentation/git-repo-config.txt +++ b/Documentation/git-repo-config.txt @@ -87,7 +87,10 @@ OPTIONS git-repo-config will ensure that the output is "true" or "false" --int:: - git-repo-config will ensure that the output is a simple decimal number + git-repo-config will ensure that the output is a simple + decimal number. An optional value suffix of 'k', 'm', or 'g' + in the config file will cause the value to be multiplied + by 1024, 1048576, or 1073741824 prior to output. ENVIRONMENT diff --git a/config.c b/config.c index fcccf7e2a4..458ae512f3 100644 --- a/config.c +++ b/config.c @@ -238,6 +238,12 @@ int git_config_int(const char *name, const char *value) int val = strtol(value, &end, 0); if (!*end) return val; + if (!strcasecmp(end, "k")) + return val * 1024; + if (!strcasecmp(end, "m")) + return val * 1024 * 1024; + if (!strcasecmp(end, "g")) + return val * 1024 * 1024 * 1024; } die("bad config value for '%s' in %s", name, config_file_name); } diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index e48a4ecdcf..a29caa06dc 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -391,5 +391,15 @@ EOF test_expect_success "rename succeeded" "diff -u expect .git/config" +test_expect_success numbers ' + + git-repo-config kilo.gram 1k && + git-repo-config mega.ton 1m && + k=$(git-repo-config --int --get kilo.gram) && + test z1024 = "z$k" && + m=$(git-repo-config --int --get mega.ton) && + test z1048576 = "z$m" +' + test_done -- cgit v1.2.1 From a862f97e98decc317437fa3b04081f68fb4ffbf3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 30 Dec 2006 22:39:24 -0800 Subject: Documentation/config.txt (and repo-config manpage): mark-up fix. Signed-off-by: Junio C Hamano --- Documentation/config.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 178e0e1e20..2f4fc25258 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -82,13 +82,13 @@ core.logAllRefUpdates:: only when the file exists. If this configuration variable is set to true, missing "$GIT_DIR/logs/" file is automatically created for branch heads. - - This information can be used to determine what commit - was the tip of a branch "2 days ago". - - This value is true by default in a repository that has - a working directory associated with it, and false by - default in a bare repository. ++ +This information can be used to determine what commit +was the tip of a branch "2 days ago". ++ +This value is true by default in a repository that has +a working directory associated with it, and false by +default in a bare repository. core.repositoryFormatVersion:: Internal variable identifying the repository format and layout -- cgit v1.2.1