diff --git a/Documentation/git.txt b/Documentation/git.txt index d00cc3ea5219f73aac79709e683e135548555fd3..ce3058182fead833c45daf02a2806f151b15f61f 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -615,6 +615,13 @@ git Diffs gitlink:git-diff-files[1]; gitlink:git-diff-tree[1] +other +~~~~~ +'GIT_TRACE':: + If this variable is set git will print `trace:` messages on + stderr telling about alias expansion, built-in command + execution and external command execution. + Discussion[[Discussion]] ------------------------ include::README[] diff --git a/exec_cmd.c b/exec_cmd.c index c1539d12ce9e350811b5b110206f5577a151e8ef..62f51fcd6e367d2dc7e3dc8d967ee05fd1648d04 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -1,5 +1,6 @@ #include "cache.h" #include "exec_cmd.h" +#include "quote.h" #define MAX_ARGS 32 extern char **environ; @@ -96,9 +97,27 @@ int execv_git_cmd(const char **argv) tmp = argv[0]; argv[0] = git_command; + if (getenv("GIT_TRACE")) { + const char **p = argv; + fputs("trace: exec:", stderr); + while (*p) { + fputc(' ', stderr); + sq_quote_print(stderr, *p); + ++p; + } + putc('\n', stderr); + fflush(stderr); + } + /* execve() can only ever return if it fails */ execve(git_command, (char **)argv, environ); + if (getenv("GIT_TRACE")) { + fprintf(stderr, "trace: exec failed: %s\n", + strerror(errno)); + fflush(stderr); + } + argv[0] = tmp; } return -1; diff --git a/git.c b/git.c index fee71383c6e6ca0374e8356c8b55570d00f93ea9..102735af6c0cfb496a04593ba466a9fbb18f693d 100644 --- a/git.c +++ b/git.c @@ -11,6 +11,7 @@ #include "git-compat-util.h" #include "exec_cmd.h" #include "cache.h" +#include "quote.h" #include "builtin.h" @@ -120,6 +121,18 @@ static int handle_alias(int *argcp, const char ***argv) if (!strcmp(alias_command, new_argv[0])) die("recursive alias: %s", alias_command); + if (getenv("GIT_TRACE")) { + int i; + fprintf(stderr, "trace: alias expansion: %s =>", + alias_command); + for (i = 0; i < count; ++i) { + fputc(' ', stderr); + sq_quote_print(stderr, new_argv[i]); + } + fputc('\n', stderr); + fflush(stderr); + } + /* insert after command name */ if (*argcp > 1) { new_argv = realloc(new_argv, sizeof(char*) * @@ -203,6 +216,18 @@ static void handle_internal_command(int argc, const char **argv, char **envp) struct cmd_struct *p = commands+i; if (strcmp(p->cmd, cmd)) continue; + + if (getenv("GIT_TRACE")) { + int i; + fprintf(stderr, "trace: built-in: git"); + for (i = 0; i < argc; ++i) { + fputc(' ', stderr); + sq_quote_print(stderr, argv[i]); + } + putc('\n', stderr); + fflush(stderr); + } + exit(p->fn(argc, argv, envp)); } } diff --git a/quote.c b/quote.c index 1910d000a5d288734aaea24da617481223ff9f56..e220dcc280d9ed6be2e2357e2660c7e828f3631b 100644 --- a/quote.c +++ b/quote.c @@ -45,6 +45,23 @@ size_t sq_quote_buf(char *dst, size_t n, const char *src) return len; } +void sq_quote_print(FILE *stream, const char *src) +{ + char c; + + fputc('\'', stream); + while ((c = *src++)) { + if (need_bs_quote(c)) { + fputs("'\\", stream); + fputc(c, stream); + fputc('\'', stream); + } else { + fputc(c, stream); + } + } + fputc('\'', stream); +} + char *sq_quote(const char *src) { char *buf; diff --git a/quote.h b/quote.h index c1ab3788e6d69318638142ebeffc690318a0489a..fc5481e78a6baad9ad72014318a9d0bfdd495b6b 100644 --- a/quote.h +++ b/quote.h @@ -29,6 +29,7 @@ */ extern char *sq_quote(const char *src); +extern void sq_quote_print(FILE *stream, const char *src); extern size_t sq_quote_buf(char *dst, size_t n, const char *src); /* This unwraps what sq_quote() produces in place, but returns diff --git a/t/test-lib.sh b/t/test-lib.sh index b0d7990a669cb053e5112bd459e9ecaffbd4c504..470a909891bc1358163af91513972ce7d0c702c0 100755 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -28,6 +28,7 @@ unset GIT_DIR unset GIT_EXTERNAL_DIFF unset GIT_INDEX_FILE unset GIT_OBJECT_DIRECTORY +unset GIT_TRACE unset SHA1_FILE_DIRECTORIES unset SHA1_FILE_DIRECTORY export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME