Skip to content
Browse files

Added a compiled wrapper to replace the git.cmd script.

This addresses github issue #36 which points out problems in handling
git commit notations of the form tag^{commit} and HEAD^. The windows
command shell uses caret as a quote both on the command line and in
batch scripts and this results in requiring double quoting. To be
able to handle both "tag^{commit}" and tag^^{commit} (either style
of command prompt quoting) the script needs replacing. This also makes
it simpler to call git from batch scripts as it will no longer need to be
prefixed with 'call'.

Signed-off-by: Pat Thoyts <patthoyts@users.sourceforge.net>
  • Loading branch information...
1 parent cb9836b commit 893b221982321303e1a31b2098cd115c65ca49ab @patthoyts patthoyts committed
Showing with 201 additions and 0 deletions.
  1. +4 −0 src/git-wrapper/.gitignore
  2. +16 −0 src/git-wrapper/Makefile
  3. +160 −0 src/git-wrapper/git-wrapper.c
  4. +21 −0 src/git-wrapper/release.sh
View
4 src/git-wrapper/.gitignore
@@ -0,0 +1,4 @@
+*.exe
+*.o
+*~
+
View
16 src/git-wrapper/Makefile
@@ -0,0 +1,16 @@
+CC = gcc
+CFLAGS = -Wall -Wwrite-strings
+LD = gcc
+LDFLAGS = -Wall -s
+LIBS =-lshell32 -lshlwapi
+
+all: git-wrapper
+
+git-wrapper: git-wrapper.o
+ $(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+clean:
+ -rm -f git-wrapper.o git-wrapper.exe
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c $^ -o $@
View
160 src/git-wrapper/git-wrapper.c
@@ -0,0 +1,160 @@
+/*
+ * git-wrapper - replace cmd\git.cmd with an executable
+ *
+ * Copyright (C) 2012 Pat Thoyts <patthoyts@users.sourceforge.net>
+ */
+
+#define STRICT
+#define WIN32_LEAN_AND_MEAN
+#define UNICODE
+#define _UNICODE
+#include <windows.h>
+#include <shlwapi.h>
+#include <shellapi.h>
+
+#ifdef __MSC_VER__
+int __stdcall wmain(void)
+#else
+int main(void)
+#endif
+{
+ int r = 1, wait = 1;
+ WCHAR exepath[MAX_PATH], exe[MAX_PATH];
+ LPWSTR cmd = NULL, path2 = NULL, exep = exe;
+ UINT codepage = 0;
+ int len;
+
+ /* get the installation location */
+ GetModuleFileName(NULL, exepath, MAX_PATH);
+ PathRemoveFileSpec(exepath);
+ PathRemoveFileSpec(exepath);
+
+ /* set the default exe module */
+ wcscpy(exe, exepath);
+ PathAppend(exe, L"bin\\git.exe");
+
+ /* if not set, set TERM to msys */
+ if (GetEnvironmentVariable(L"TERM", NULL, 0) == 0) {
+ SetEnvironmentVariable(L"TERM", L"msys");
+ }
+
+ /* if not set, set PLINK_PROTOCOL to ssh */
+ if (GetEnvironmentVariable(L"PLINK_PROTOCOL", NULL, 0) == 0) {
+ SetEnvironmentVariable(L"PLINK_PROTOCOL", L"ssh");
+ }
+
+ /* set HOME to %HOMEDRIVE%%HOMEPATH% or %USERPROFILE%
+ * With roaming profiles: HOMEPATH is the roaming location and
+ * USERPROFILE is the local location
+ */
+ if (GetEnvironmentVariable(L"HOME", NULL, 0) == 0) {
+ LPWSTR e = NULL;
+ len = GetEnvironmentVariable(L"HOMEPATH", NULL, 0);
+ if (len == 0) {
+ len = GetEnvironmentVariable(L"USERPROFILE", NULL, 0);
+ if (len != 0) {
+ e = (LPWSTR)malloc(len * sizeof(WCHAR));
+ GetEnvironmentVariable(L"USERPROFILE", e, len);
+ SetEnvironmentVariable(L"HOME", e);
+ free(e);
+ }
+ } else {
+ int n;
+ len += GetEnvironmentVariable(L"HOMEDRIVE", NULL, 0);
+ e = (LPWSTR)malloc(sizeof(WCHAR) * (len + 2));
+ n = GetEnvironmentVariable(L"HOMEDRIVE", e, len);
+ GetEnvironmentVariable(L"HOMEPATH", &e[n], len-n);
+ SetEnvironmentVariable(L"HOME", e);
+ free(e);
+ }
+ }
+
+ /* extend the PATH */
+ len = GetEnvironmentVariable(L"PATH", NULL, 0);
+ len = sizeof(WCHAR) * (len + 2 * MAX_PATH);
+ path2 = (LPWSTR)malloc(len);
+ wcscpy(path2, exepath);
+ PathAppend(path2, L"bin;");
+ /* should do this only if it exists */
+ wcscat(path2, exepath);
+ PathAppend(path2, L"mingw\\bin;");
+ GetEnvironmentVariable(L"PATH", &path2[wcslen(path2)],
+ (len/sizeof(WCHAR))-wcslen(path2));
+ SetEnvironmentVariable(L"PATH", path2);
+ free(path2);
+
+
+ /* fix up the command line to call git.exe
+ * We have to be very careful about quoting here so we just
+ * trim off the first argument and replace it leaving the rest
+ * untouched.
+ */
+ {
+ int wargc = 0, gui = 0;
+ LPWSTR cmdline = NULL;
+ LPWSTR *wargv = NULL, p = NULL;
+ cmdline = GetCommandLine();
+ wargv = CommandLineToArgvW(cmdline, &wargc);
+ cmd = (LPWSTR)malloc(sizeof(WCHAR) * (wcslen(cmdline) + MAX_PATH));
+ if (wargc > 1 && wcsicmp(L"gui", wargv[1]) == 0) {
+ wait = 0;
+ if (wargc > 2 && wcsicmp(L"citool", wargv[2]) == 0) {
+ wait = 1;
+ wcscpy(cmd, L"git.exe");
+ } else {
+ WCHAR script[MAX_PATH];
+ gui = 1;
+ wcscat(script, exepath);
+ PathAppend(script, L"libexec\\git-core\\git-gui");
+ PathQuoteSpaces(script);
+ wcscpy(cmd, L"wish.exe ");
+ wcscat(cmd, script);
+ wcscat(cmd, L" --");
+ exep = NULL; /* find the module from the commandline */
+ }
+ } else {
+ wcscpy(cmd, L"git.exe");
+ }
+ /* find the first space after the initial parameter then append all */
+ p = wcschr(&cmdline[wcslen(wargv[0])], L' ');
+ if (p && *p) {
+ /* for git gui subcommands, remove the 'gui' word */
+ if (gui) {
+ while (*p == L' ') ++p;
+ p = wcschr(p, L' ');
+ }
+ if (p && *p)
+ wcscat(cmd, p);
+ }
+ LocalFree(wargv);
+ }
+
+ /* set the console to ANSI/GUI codepage */
+ codepage = GetConsoleCP();
+ SetConsoleCP(GetACP());
+
+ {
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
+ ZeroMemory(&si, sizeof(STARTUPINFO));
+ si.cb = sizeof(STARTUPINFO);
+ CreateProcess(exep,/* module: null means use command line */
+ cmd, /* modified command line */
+ NULL, /* process handle inheritance */
+ NULL, /* thread handle inheritance */
+ TRUE, /* handles inheritable? */
+ CREATE_UNICODE_ENVIRONMENT,
+ NULL, /* environment: use parent */
+ NULL, /* starting directory: use parent */
+ &si, &pi);
+ if (wait)
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ }
+
+ free(cmd);
+
+ /* reset the console codepage */
+ SetConsoleCP(codepage);
+ ExitProcess(r);
+}
View
21 src/git-wrapper/release.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+cd "$(dirname "$0")"
+
+DEST=/cmd/git.exe
+
+die () {
+ echo "$*" >&2
+ exit 1
+}
+
+rmscript () {
+ test -f /cmd/git.cmd && rm /cmd/git.cmd || true
+}
+
+make &&
+index=$(/share/msysGit/pre-install.sh) &&
+rmscript &&
+install -m 775 git-wrapper.exe $DEST &&
+/share/msysGit/post-install.sh $index "Updated git wrapper exe" ||
+die "Failed to update git wrapper executable"

0 comments on commit 893b221

Please sign in to comment.
Something went wrong with that request. Please try again.