Merge pull request #1932 from dscho/prepare-for-2.20.0-rc0

Prepare for v2.20.0-rc0
This commit is contained in:
Johannes Schindelin
2018-11-16 16:48:55 +01:00
committed by GitHub
20 changed files with 706 additions and 830 deletions

View File

@@ -164,7 +164,7 @@ phases:
displayName: Windows
condition: succeeded()
queue:
name: Hosted VS2017
name: Hosted
timeoutInMinutes: 240
steps:
- powershell: |
@@ -215,7 +215,7 @@ phases:
. ci/lib.sh
make -j10 DEVELOPER=1 NO_PERL=1 || exit 1
NO_PERL=1 NO_SVN_TESTS=1 GIT_TEST_OPTS=\"--quiet --write-junit-xml\" time make -j15 -k DEVELOPER=1 test || {
NO_PERL=1 NO_SVN_TESTS=1 GIT_TEST_OPTS=\"--no-chain-lint --no-bin-wrappers --quiet --write-junit-xml\" time make -j15 -k DEVELOPER=1 test || {
NO_PERL=1 NO_SVN_TESTS=1 GIT_TEST_OPTS=\"-i -v -x\" make -k -C t failed; exit 1
}

View File

@@ -22,6 +22,7 @@
#include "wt-status.h"
#include "revision.h"
#include "rerere.h"
#include "branch.h"
static char const * const builtin_rebase_usage[] = {
N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
@@ -54,7 +55,7 @@ static int use_builtin_rebase(void)
cp.git_cmd = 1;
if (capture_command(&cp, &out, 6)) {
strbuf_release(&out);
return 0;
return 1;
}
strbuf_trim(&out);
@@ -281,8 +282,10 @@ static int apply_autostash(struct rebase_options *opts)
if (!file_exists(path))
return 0;
if (read_one(state_dir_path("autostash", opts), &autostash))
if (read_one(path, &autostash))
return error(_("Could not read '%s'"), path);
/* Ensure that the hash is not mistaken for a number */
strbuf_addstr(&autostash, "^0");
argv_array_pushl(&stash_apply.args,
"stash", "apply", autostash.buf, NULL);
stash_apply.git_cmd = 1;
@@ -364,9 +367,124 @@ N_("Resolve all conflicts manually, mark them as resolved with\n"
"To abort and get back to the state before \"git rebase\", run "
"\"git rebase --abort\".");
#define GIT_REFLOG_ACTION_ENVIRONMENT "GIT_REFLOG_ACTION"
#define RESET_HEAD_DETACH (1<<0)
#define RESET_HEAD_HARD (1<<1)
static int reset_head(struct object_id *oid, const char *action,
const char *switch_to_branch, int detach_head,
const char *reflog_orig_head, const char *reflog_head);
const char *switch_to_branch, unsigned flags,
const char *reflog_orig_head, const char *reflog_head)
{
unsigned detach_head = flags & RESET_HEAD_DETACH;
unsigned reset_hard = flags & RESET_HEAD_HARD;
struct object_id head_oid;
struct tree_desc desc[2] = { { NULL }, { NULL } };
struct lock_file lock = LOCK_INIT;
struct unpack_trees_options unpack_tree_opts;
struct tree *tree;
const char *reflog_action;
struct strbuf msg = STRBUF_INIT;
size_t prefix_len;
struct object_id *orig = NULL, oid_orig,
*old_orig = NULL, oid_old_orig;
int ret = 0, nr = 0;
if (switch_to_branch && !starts_with(switch_to_branch, "refs/"))
BUG("Not a fully qualified branch: '%s'", switch_to_branch);
if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0) {
ret = -1;
goto leave_reset_head;
}
if ((!oid || !reset_hard) && get_oid("HEAD", &head_oid)) {
ret = error(_("could not determine HEAD revision"));
goto leave_reset_head;
}
if (!oid)
oid = &head_oid;
memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));
setup_unpack_trees_porcelain(&unpack_tree_opts, action);
unpack_tree_opts.head_idx = 1;
unpack_tree_opts.src_index = the_repository->index;
unpack_tree_opts.dst_index = the_repository->index;
unpack_tree_opts.fn = reset_hard ? oneway_merge : twoway_merge;
unpack_tree_opts.update = 1;
unpack_tree_opts.merge = 1;
if (!detach_head)
unpack_tree_opts.reset = 1;
if (read_index_unmerged(the_repository->index) < 0) {
ret = error(_("could not read index"));
goto leave_reset_head;
}
if (!reset_hard && !fill_tree_descriptor(&desc[nr++], &head_oid)) {
ret = error(_("failed to find tree of %s"), oid_to_hex(oid));
goto leave_reset_head;
}
if (!fill_tree_descriptor(&desc[nr++], oid)) {
ret = error(_("failed to find tree of %s"), oid_to_hex(oid));
goto leave_reset_head;
}
if (unpack_trees(nr, desc, &unpack_tree_opts)) {
ret = -1;
goto leave_reset_head;
}
tree = parse_tree_indirect(oid);
prime_cache_tree(the_repository->index, tree);
if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0) {
ret = error(_("could not write index"));
goto leave_reset_head;
}
reflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);
strbuf_addf(&msg, "%s: ", reflog_action ? reflog_action : "rebase");
prefix_len = msg.len;
if (!get_oid("ORIG_HEAD", &oid_old_orig))
old_orig = &oid_old_orig;
if (!get_oid("HEAD", &oid_orig)) {
orig = &oid_orig;
if (!reflog_orig_head) {
strbuf_addstr(&msg, "updating ORIG_HEAD");
reflog_orig_head = msg.buf;
}
update_ref(reflog_orig_head, "ORIG_HEAD", orig, old_orig, 0,
UPDATE_REFS_MSG_ON_ERR);
} else if (old_orig)
delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
if (!reflog_head) {
strbuf_setlen(&msg, prefix_len);
strbuf_addstr(&msg, "updating HEAD");
reflog_head = msg.buf;
}
if (!switch_to_branch)
ret = update_ref(reflog_head, "HEAD", oid, orig,
detach_head ? REF_NO_DEREF : 0,
UPDATE_REFS_MSG_ON_ERR);
else {
ret = create_symref("HEAD", switch_to_branch, msg.buf);
if (!ret)
ret = update_ref(reflog_head, "HEAD", oid, NULL, 0,
UPDATE_REFS_MSG_ON_ERR);
}
leave_reset_head:
strbuf_release(&msg);
rollback_lock_file(&lock);
while (nr)
free((void *)desc[--nr].buffer);
return ret;
}
static int move_to_original_branch(struct rebase_options *opts)
{
@@ -697,112 +815,6 @@ finished_rebase:
return status ? -1 : 0;
}
#define GIT_REFLOG_ACTION_ENVIRONMENT "GIT_REFLOG_ACTION"
static int reset_head(struct object_id *oid, const char *action,
const char *switch_to_branch, int detach_head,
const char *reflog_orig_head, const char *reflog_head)
{
struct object_id head_oid;
struct tree_desc desc;
struct lock_file lock = LOCK_INIT;
struct unpack_trees_options unpack_tree_opts;
struct tree *tree;
const char *reflog_action;
struct strbuf msg = STRBUF_INIT;
size_t prefix_len;
struct object_id *orig = NULL, oid_orig,
*old_orig = NULL, oid_old_orig;
int ret = 0;
if (switch_to_branch && !starts_with(switch_to_branch, "refs/"))
BUG("Not a fully qualified branch: '%s'", switch_to_branch);
if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)
return -1;
if (!oid) {
if (get_oid("HEAD", &head_oid)) {
rollback_lock_file(&lock);
return error(_("could not determine HEAD revision"));
}
oid = &head_oid;
}
memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));
setup_unpack_trees_porcelain(&unpack_tree_opts, action);
unpack_tree_opts.head_idx = 1;
unpack_tree_opts.src_index = the_repository->index;
unpack_tree_opts.dst_index = the_repository->index;
unpack_tree_opts.fn = oneway_merge;
unpack_tree_opts.update = 1;
unpack_tree_opts.merge = 1;
if (!detach_head)
unpack_tree_opts.reset = 1;
if (read_index_unmerged(the_repository->index) < 0) {
rollback_lock_file(&lock);
return error(_("could not read index"));
}
if (!fill_tree_descriptor(&desc, oid)) {
error(_("failed to find tree of %s"), oid_to_hex(oid));
rollback_lock_file(&lock);
free((void *)desc.buffer);
return -1;
}
if (unpack_trees(1, &desc, &unpack_tree_opts)) {
rollback_lock_file(&lock);
free((void *)desc.buffer);
return -1;
}
tree = parse_tree_indirect(oid);
prime_cache_tree(the_repository->index, tree);
if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0)
ret = error(_("could not write index"));
free((void *)desc.buffer);
if (ret)
return ret;
reflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);
strbuf_addf(&msg, "%s: ", reflog_action ? reflog_action : "rebase");
prefix_len = msg.len;
if (!get_oid("ORIG_HEAD", &oid_old_orig))
old_orig = &oid_old_orig;
if (!get_oid("HEAD", &oid_orig)) {
orig = &oid_orig;
if (!reflog_orig_head) {
strbuf_addstr(&msg, "updating ORIG_HEAD");
reflog_orig_head = msg.buf;
}
update_ref(reflog_orig_head, "ORIG_HEAD", orig, old_orig, 0,
UPDATE_REFS_MSG_ON_ERR);
} else if (old_orig)
delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
if (!reflog_head) {
strbuf_setlen(&msg, prefix_len);
strbuf_addstr(&msg, "updating HEAD");
reflog_head = msg.buf;
}
if (!switch_to_branch)
ret = update_ref(reflog_head, "HEAD", oid, orig, REF_NO_DEREF,
UPDATE_REFS_MSG_ON_ERR);
else {
ret = create_symref("HEAD", switch_to_branch, msg.buf);
if (!ret)
ret = update_ref(reflog_head, "HEAD", oid, NULL, 0,
UPDATE_REFS_MSG_ON_ERR);
}
strbuf_release(&msg);
return ret;
}
static int rebase_config(const char *var, const char *value, void *data)
{
struct rebase_options *opts = data;
@@ -1177,8 +1189,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
rerere_clear(&merge_rr);
string_list_clear(&merge_rr, 1);
if (reset_head(NULL, "reset", NULL, 0, NULL, NULL) < 0)
if (reset_head(NULL, "reset", NULL, RESET_HEAD_HARD,
NULL, NULL) < 0)
die(_("could not discard worktree changes"));
remove_branch_state();
if (read_basic_state(&options))
exit(1);
goto run_rebase;
@@ -1193,9 +1207,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (read_basic_state(&options))
exit(1);
if (reset_head(&options.orig_head, "reset",
options.head_name, 0, NULL, NULL) < 0)
options.head_name, RESET_HEAD_HARD,
NULL, NULL) < 0)
die(_("could not move back to %s"),
oid_to_hex(&options.orig_head));
remove_branch_state();
ret = finish_rebase(&options);
goto cleanup;
}
@@ -1395,15 +1411,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
* git-rebase.txt caveats with "unless you know what you are doing"
*/
if (options.rebase_merges)
die(_("error: cannot combine '--preserve_merges' with "
die(_("error: cannot combine '--preserve-merges' with "
"'--rebase-merges'"));
if (options.rebase_merges) {
if (strategy_options.nr)
die(_("error: cannot combine '--rebase_merges' with "
die(_("error: cannot combine '--rebase-merges' with "
"'--strategy-option'"));
if (options.strategy)
die(_("error: cannot combine '--rebase_merges' with "
die(_("error: cannot combine '--rebase-merges' with "
"'--strategy'"));
}
@@ -1528,7 +1544,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
update_index_if_able(&the_index, &lock_file);
rollback_lock_file(&lock_file);
if (has_unstaged_changes(0) || has_uncommitted_changes(0)) {
if (has_unstaged_changes(1) || has_uncommitted_changes(1)) {
const char *autostash =
state_dir_path("autostash", &options);
struct child_process stash = CHILD_PROCESS_INIT;
@@ -1554,10 +1570,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (safe_create_leading_directories_const(autostash))
die(_("Could not create directory for '%s'"),
options.state_dir);
write_file(autostash, "%s", buf.buf);
write_file(autostash, "%s", oid_to_hex(&oid));
printf(_("Created autostash: %s\n"), buf.buf);
if (reset_head(&head->object.oid, "reset --hard",
NULL, 0, NULL, NULL) < 0)
NULL, RESET_HEAD_HARD, NULL, NULL) < 0)
die(_("could not reset --hard"));
printf(_("HEAD is now at %s"),
find_unique_abbrev(&head->object.oid,
@@ -1677,8 +1693,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
"it...\n"));
strbuf_addf(&msg, "rebase: checkout %s", options.onto_name);
if (reset_head(&options.onto->object.oid, "checkout", NULL, 1,
NULL, msg.buf))
if (reset_head(&options.onto->object.oid, "checkout", NULL,
RESET_HEAD_DETACH, NULL, msg.buf))
die(_("Could not detach HEAD"));
strbuf_release(&msg);

File diff suppressed because it is too large Load Diff

View File

@@ -8,9 +8,9 @@
#include "../cache.h"
#include "win32/exit-process.h"
#include "win32/lazyload.h"
#include "../config.h"
#include "../string-list.h"
#include "../attr.h"
#include "../config.h"
#define HCAST(type, handle) ((type)(intptr_t)handle)
@@ -819,13 +819,11 @@ static int current_directory_len = 0;
int mingw_chdir(const char *dirname)
{
int result;
DECLARE_PROC_ADDR(kernel32.dll, DWORD, GetFinalPathNameByHandleW,
HANDLE, LPWSTR, DWORD, DWORD);
wchar_t wdirname[MAX_LONG_PATH];
if (xutftowcs_long_path(wdirname, dirname) < 0)
return -1;
if (has_symlinks && INIT_PROC_ADDR(GetFinalPathNameByHandleW)) {
if (has_symlinks) {
HANDLE hnd = CreateFileW(wdirname, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
@@ -962,12 +960,15 @@ static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
errno = err_win_to_posix(GetLastError());
return -1;
}
buf->st_ino = 0;
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
buf->st_gid = buf->st_uid = 0;
buf->st_gid = 0;
buf->st_uid = 0;
buf->st_nlink = 1;
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes, 0, NULL);
buf->st_size = fdata.nFileSizeLow | (((off_t) fdata.nFileSizeHigh) << 32);
buf->st_size = fdata.nFileSizeLow |
(((off_t)fdata.nFileSizeHigh)<<32);
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
@@ -1176,8 +1177,6 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
char *mingw_getcwd(char *pointer, int len)
{
wchar_t cwd[MAX_PATH], wpointer[MAX_PATH];
DECLARE_PROC_ADDR(kernel32.dll, DWORD, GetFinalPathNameByHandleW,
HANDLE, LPWSTR, DWORD, DWORD);
DWORD ret = GetCurrentDirectoryW(ARRAY_SIZE(cwd), cwd);
if (!ret || ret >= ARRAY_SIZE(cwd)) {
@@ -1185,8 +1184,7 @@ char *mingw_getcwd(char *pointer, int len)
return NULL;
}
ret = GetLongPathNameW(cwd, wpointer, ARRAY_SIZE(wpointer));
if (!ret && GetLastError() == ERROR_ACCESS_DENIED &&
INIT_PROC_ADDR(GetFinalPathNameByHandleW)) {
if (!ret && GetLastError() == ERROR_ACCESS_DENIED) {
HANDLE hnd = CreateFileW(cwd, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
@@ -1209,8 +1207,8 @@ char *mingw_getcwd(char *pointer, int len)
}
/*
* See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
* (Parsing C++ Command-Line Arguments)
* See "Parsing C++ Command-Line Arguments" at Microsoft's Docs:
* https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments
*/
static const char *quote_arg_msvc(const char *arg)
{
@@ -1452,34 +1450,37 @@ static char *path_lookup(const char *cmd, int exe_only)
return prog;
}
#if defined(_MSC_VER)
/* We need a stable sort */
#ifndef INTERNAL_QSORT
#include "qsort.c"
#endif
static const wchar_t *wcschrnul(const wchar_t *s, wchar_t c)
{
while (*s && *s != c)
s++;
return s;
}
/* Compare only keys */
static int wenvcmp(const void *a, const void *b)
{
wchar_t *p = *(wchar_t **)a, *q = *(wchar_t **)b;
size_t p_len, q_len;
int ret;
/* Find end of keys */
for (p_len = 0; p[p_len] && p[p_len] != L'='; p_len++)
; /* do nothing */
for (q_len = 0; q[q_len] && q[q_len] != L'='; q_len++)
; /* do nothing */
/* Find the keys */
p_len = wcschrnul(p, L'=') - p;
q_len = wcschrnul(q, L'=') - q;
/* Are keys identical (modulo case)? */
if (p_len == q_len && !_wcsnicmp(p, q, p_len))
return 0;
/* If the length differs, include the shorter key's NUL */
if (p_len < q_len)
p_len++;
else if (p_len > q_len)
p_len = q_len + 1;
ret = _wcsnicmp(p, q, p_len < q_len ? p_len : q_len);
return ret ? ret : (p_len < q_len ? -1 : +1);
return _wcsnicmp(p, q, p_len);
}
/* We need a stable sort to convert the environment between UTF-16 <-> UTF-8 */
#ifndef INTERNAL_QSORT
#include "qsort.c"
#endif
/*
* Build an environment block combining the inherited environment
* merged with the given list of settings.
@@ -1494,25 +1495,15 @@ static int wenvcmp(const void *a, const void *b)
*/
static wchar_t *make_environment_block(char **deltaenv)
{
/*
* The CRT (at least as of UCRT) secretly declares "_wenviron"
* as a function that returns a pointer to a mostly static table.
* Grab the pointer and cache it for the duration of our loop.
*/
const wchar_t *wenv = GetEnvironmentStringsW(), *p;
size_t delta_size = 0, size = 1; /* for extra NUL at the end */
wchar_t *wenv = GetEnvironmentStringsW(), *wdeltaenv, *result, *p;
size_t wlen, s, delta_size, size;
wchar_t **array = NULL;
size_t alloc = 0, nr = 0, i;
const char *p2;
wchar_t *wdeltaenv;
size = 1; /* for extra NUL at the end */
wchar_t *result, *p3;
/*
* If there is no deltaenv to apply, simply return a copy
*/
/* If there is no deltaenv to apply, simply return a copy. */
if (!deltaenv || !*deltaenv) {
for (p = wenv; p && *p; ) {
size_t s = wcslen(p) + 1;
@@ -1531,116 +1522,51 @@ static wchar_t *make_environment_block(char **deltaenv)
* sort them using the stable git_qsort() and then copy, skipping
* duplicate keys
*/
for (p = wenv; p && *p; ) {
size_t s = wcslen(p) + 1;
size += s;
ALLOC_GROW(array, nr + 1, alloc);
s = wcslen(p) + 1;
array[nr++] = p;
p += s;
size += s;
}
/* (over-)assess size needed for wchar version of deltaenv */
for (i = 0; deltaenv[i]; i++) {
size_t s = strlen(deltaenv[i]) + 1;
delta_size += s;
}
for (delta_size = 0, i = 0; deltaenv[i]; i++)
delta_size += strlen(deltaenv[i]) * 2 + 1;
ALLOC_ARRAY(wdeltaenv, delta_size);
/* convert the deltaenv, appending to array */
for (i = 0, p3 = wdeltaenv; deltaenv[i]; i++) {
size_t s = strlen(deltaenv[i]) + 1, wlen;
wlen = xutftowcs(p3, deltaenv[i], s * 2);
for (i = 0, p = wdeltaenv; deltaenv[i]; i++) {
ALLOC_GROW(array, nr + 1, alloc);
array[nr++] = p3;
p3 += wlen + 1;
wlen = xutftowcs(p, deltaenv[i], wdeltaenv + delta_size - p);
array[nr++] = p;
p += wlen + 1;
}
git_qsort(array, nr, sizeof(*array), wenvcmp);
ALLOC_ARRAY(result, size + delta_size);
for (p3 = result, i = 0; i < nr; i++) {
wchar_t *equal = wcschr(array[i], L'=');;
for (p = result, i = 0; i < nr; i++) {
/* Skip any duplicate keys; last one wins */
while (i + 1 < nr && !wenvcmp(array + i, array + i + 1))
i++;
/* Skip "to delete" entry */
if (!equal)
if (!wcschr(array[i], L'='))
continue;
p = array[i];
/* Skip any duplicate */
if (i + 1 < nr) {
wchar_t *next = array[i + 1];
size_t n = equal - p;
if (!_wcsnicmp(p, next, n) && (!next[n] || next[n] == L'='))
continue;
}
size = wcslen(p) + 1;
memcpy(p3, p, size * sizeof(*p));
p3 += size;
size = wcslen(array[i]) + 1;
memcpy(p, array[i], size * sizeof(*p));
p += size;
}
*p3 = L'\0';
*p = L'\0';
free(array);
free(wdeltaenv);
FreeEnvironmentStringsW(wenv);
return result;
}
#else
static int do_putenv(char **env, const char *name, int size, int free_old);
/* 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;
/* used as a indicator when the environment has been changed outside mingw.c */
static char **saved_environ;
static void maybe_reinitialize_environ(void);
/*
* Create environment block suitable for CreateProcess. Merges current
* process environment and the supplied environment changes.
*/
static wchar_t *make_environment_block(char **deltaenv)
{
wchar_t *wenvblk = NULL;
char **tmpenv;
int i = 0, size, wenvsz = 0, wenvpos = 0;
maybe_reinitialize_environ();
size = environ_size;
while (deltaenv && deltaenv[i] && *deltaenv[i])
i++;
/* copy the environment, leaving space for changes */
ALLOC_ARRAY(tmpenv, size + i);
memcpy(tmpenv, environ, size * sizeof(char*));
/* merge supplied environment changes into the temporary environment */
for (i = 0; deltaenv && deltaenv[i] && *deltaenv[i]; i++)
size = do_putenv(tmpenv, deltaenv[i], size, 0);
/* create environment block from temporary environment */
for (i = 0; tmpenv[i] && *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], tmpenv[i], size) + 1;
}
/* add final \0 terminator */
wenvblk[wenvpos] = 0;
free(tmpenv);
return wenvblk;
}
#endif
static void do_unset_environment_variables(void)
{
static int done;
@@ -2141,131 +2067,83 @@ int msc_putenv(const char *name)
#else
/*
* Compare environment entries by key (i.e. stopping at '=' or '\0').
* UTF-8 versions of getenv(), putenv() and unsetenv().
* Internally, they use the CRT's stock UNICODE routines
* to avoid data loss.
*/
static int compareenv(const void *v1, const void *v2)
{
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;
}
}
/*
* Functions implemented outside Git are able to modify the environment,
* too. For example, cURL's curl_global_init() function sets the CHARSET
* environment variable (at least in certain circumstances).
*
* Therefore we need to be *really* careful *not* to assume that we have
* sole control over the environment and reinitialize it when necessary.
*/
static void maybe_reinitialize_environ(void)
{
int i;
if (!saved_environ) {
warning("MinGW environment not initialized yet");
return;
}
if (environ_size <= 0)
return;
if (saved_environ != environ)
/* We have *no* idea how much space was allocated outside */
environ_alloc = 0;
else if (!environ[environ_size - 1])
return; /* still consistent */
for (i = 0; environ[i] && *environ[i]; i++)
; /* continue counting */
environ[i] = NULL;
environ_size = i + 1;
/* sort environment for O(log n) getenv / putenv */
qsort(environ, i, sizeof(char*), compareenv);
}
static int bsearchenv(char **env, const char *name, size_t size)
{
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 ~low; /* not found, return 1's complement of insert position */
}
/*
* 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 int do_putenv(char **env, const char *name, int size, int free_old)
{
int i = size <= 0 ? -1 : bsearchenv(env, name, size - 1);
/* 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++;
}
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;
}
char *mingw_getenv(const char *name)
{
#define GETENV_MAX_RETAIN 30
static char *values[GETENV_MAX_RETAIN];
static int value_counter;
int len_key, len_value;
wchar_t *w_key;
char *value;
int pos;
wchar_t w_value[32768];
if (environ_size <= 0)
if (!name || !*name)
return NULL;
maybe_reinitialize_environ();
pos = bsearchenv(environ, name, environ_size - 1);
if (pos < 0)
len_key = strlen(name) + 1;
/* We cannot use xcalloc() here because that uses getenv() itself */
w_key = calloc(len_key, sizeof(wchar_t));
if (!w_key)
die("Out of memory, (tried to allocate %u wchar_t's)", len_key);
xutftowcs(w_key, name, len_key);
len_value = GetEnvironmentVariableW(w_key, w_value, ARRAY_SIZE(w_value));
if (!len_value && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
free(w_key);
return NULL;
value = strchr(environ[pos], '=');
return value ? &value[1] : NULL;
}
free(w_key);
len_value = len_value * 3 + 1;
/* We cannot use xcalloc() here because that uses getenv() itself */
value = calloc(len_value, sizeof(char));
if (!value)
die("Out of memory, (tried to allocate %u bytes)", len_value);
xwcstoutf(value, w_value, len_value);
/*
* We return `value` which is an allocated value and the caller is NOT
* expecting to have to free it, so we keep a round-robin array,
* invalidating the buffer after GETENV_MAX_RETAIN getenv() calls.
*/
free(values[value_counter]);
values[value_counter++] = value;
if (value_counter >= ARRAY_SIZE(values))
value_counter = 0;
return value;
}
int mingw_putenv(const char *namevalue)
{
maybe_reinitialize_environ();
ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
saved_environ = environ;
environ_size = do_putenv(environ, namevalue, environ_size, 1);
return 0;
int size;
wchar_t *wide, *equal;
BOOL result;
if (!namevalue || !*namevalue)
return 0;
size = strlen(namevalue) * 2 + 1;
wide = calloc(size, sizeof(wchar_t));
if (!wide)
die("Out of memory, (tried to allocate %u wchar_t's)", size);
xutftowcs(wide, namevalue, size);
equal = wcschr(wide, L'=');
if (!equal)
result = SetEnvironmentVariableW(wide, NULL);
else {
*equal = L'\0';
result = SetEnvironmentVariableW(wide, equal + 1);
}
free(wide);
if (!result)
errno = err_win_to_posix(GetLastError());
return result ? 0 : -1;
}
#endif
@@ -3284,42 +3162,35 @@ static BOOL WINAPI handle_ctrl_c(DWORD ctrl_type)
return TRUE; /* we did handle this */
}
#if defined(_MSC_VER)
#ifdef _MSC_VER
#ifdef _DEBUG
#include <crtdbg.h>
#endif
#endif
/*
* This routine sits between wmain() and "main" in git.exe.
* We receive UNICODE (wchar_t) values for argv and env.
* We implement wmain() and compile with -municode, which would
* normally ignore main(), but we call the latter from the former
* so that we can handle non-ASCII command-line parameters
* appropriately.
*
* To be more compatible with the core git code, we convert
* argv into UTF8 and pass them directly to the "main" routine.
*
* We don't bother converting the given UNICODE env vector,
* but rather leave them in the CRT. We replaced the various
* getenv/putenv routines to pull them directly from the CRT.
*
* This is unlike the MINGW version:
* [] It does the UNICODE-2-UTF8 conversion on both sets and
* stuffs the values back into the CRT using exported symbols.
* [] It also maintains a private copy of the environment and
* tries to track external changes to it.
* argv into UTF8 and pass them directly to main().
*/
int msc_startup(int argc, wchar_t **w_argv, wchar_t **w_env)
int wmain(int argc, const wchar_t **wargv)
{
char **my_utf8_argv = NULL, **save = NULL;
char *buffer = NULL;
int maxlen;
int k, exit_status;
int i, maxlen, exit_status;
char *buffer, **save;
const char **argv;
#ifdef _MSC_VER
#ifdef _DEBUG
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
#endif
#ifdef USE_MSVC_CRTDBG
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
#endif
SetConsoleCtrlHandler(handle_ctrl_c, TRUE);
@@ -3328,10 +3199,10 @@ int msc_startup(int argc, wchar_t **w_argv, wchar_t **w_env)
adjust_symlink_flags();
fsync_object_files = 1;
/* determine size of argv conversion buffer */
maxlen = wcslen(_wpgmptr);
for (k = 1; k < argc; k++)
maxlen = max(maxlen, wcslen(w_argv[k]));
/* determine size of argv and environ conversion buffer */
maxlen = wcslen(wargv[0]);
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;
@@ -3342,13 +3213,11 @@ int msc_startup(int argc, wchar_t **w_argv, wchar_t **w_env)
* to remember all the string pointers because parse_options()
* will remove claimed items from the argv that we pass down.
*/
ALLOC_ARRAY(my_utf8_argv, argc + 1);
ALLOC_ARRAY(argv, argc + 1);
ALLOC_ARRAY(save, argc + 1);
save[0] = my_utf8_argv[0] = wcstoutfdup_startup(buffer, _wpgmptr, maxlen);
for (k = 1; k < argc; k++)
save[k] = my_utf8_argv[k] = wcstoutfdup_startup(buffer, w_argv[k], maxlen);
save[k] = my_utf8_argv[k] = NULL;
for (i = 0; i < argc; i++)
argv[i] = save[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
argv[i] = save[i] = NULL;
free(buffer);
/* fix Windows specific environment settings */
@@ -3373,102 +3242,16 @@ int msc_startup(int argc, wchar_t **w_argv, wchar_t **w_env)
current_directory_len = GetCurrentDirectoryW(0, NULL);
/* invoke the real main() using our utf8 version of argv. */
exit_status = msc_main(argc, my_utf8_argv);
exit_status = main(argc, argv);
for (k = 0; k < argc; k++)
free(save[k]);
for (i = 0; i < argc; i++)
free(save[i]);
free(save);
free(my_utf8_argv);
free(argv);
return exit_status;
}
#else
void mingw_startup(void)
{
int i, maxlen, argc;
char *buffer;
wchar_t **wenv, **wargv;
_startupinfo si;
SetConsoleCtrlHandler(handle_ctrl_c, TRUE);
maybe_redirect_std_handles();
adjust_symlink_flags();
fsync_object_files = 1;
/* get wide char arguments and environment */
si.newmode = 0;
if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
die_startup();
/* determine size of argv and environ conversion buffer */
maxlen = wcslen(wargv[0]);
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. Note that xmalloc / xmemdupz etc. call getenv, so we cannot
* use it while initializing the environment itself.
*/
environ_size = i + 1;
environ_alloc = alloc_nr(environ_size * sizeof(char*));
saved_environ = environ = malloc_startup(environ_alloc);
/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
maxlen = 3 * maxlen + 1;
buffer = malloc_startup(maxlen);
/* convert command line arguments and environment to UTF-8 */
for (i = 0; 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);
/* sort environment for O(log n) getenv / putenv */
qsort(environ, i, sizeof(char*), compareenv);
/* fix Windows specific environment settings */
setup_windows_environment();
unset_environment_variables = xstrdup("PERL5LIB");
/*
* Avoid a segmentation fault when cURL tries to set the CHARSET
* variable and putenv() barfs at our nedmalloc'ed environment.
*/
if (!getenv("CHARSET")) {
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "cp%u", GetACP());
setenv("CHARSET", buf.buf, 1);
strbuf_release(&buf);
}
/* initialize critical section for waitpid pinfo_t list */
InitializeCriticalSection(&pinfo_cs);
InitializeCriticalSection(&phantom_symlinks_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);
/* initialize Unicode console */
winansi_init();
/* init length of current directory for handle_long_path */
current_directory_len = GetCurrentDirectoryW(0, NULL);
}
#endif
int uname(struct utsname *buf)
{
unsigned v = (unsigned)GetVersion();

View File

@@ -262,12 +262,11 @@ char *mingw_getcwd(char *pointer, int len);
#define getcwd mingw_getcwd
#ifdef NO_UNSETENV
#error "NO_UNSETENV is incompatible with the MinGW startup code!"
#error "NO_UNSETENV is incompatible with the Windows-specific startup code!"
#endif
#if defined(_MSC_VER)
/*
* We bind *env() routines (even the mingw_ ones) to private msc_ versions.
* We bind *env() routines (even the mingw_ ones) to private mingw_ versions.
* These talk to the CRT using UNICODE/wchar_t, but maintain the original
* narrow-char API.
*
@@ -276,7 +275,7 @@ char *mingw_getcwd(char *pointer, int len);
* (and secretly updates both when you set one or the other), but it uses CP_ACP
* to do the conversion rather than CP_UTF8.
*
* Since everything in the git code base is UTF8, we define the msc_ routines
* Since everything in the git code base is UTF8, we define the mingw_ routines
* to access the CRT using the UNICODE routines and manually convert them to
* UTF8. This also avoids round-trip problems.
*
@@ -284,33 +283,13 @@ char *mingw_getcwd(char *pointer, int len);
* from the CRT. But to access "_environ" we would have to statically link
* to the CRT (/MT).
*
* We also use "wmain(argc,argv,env)" and get the initial UNICODE setup for us.
* This avoids the need for the msc_startup() to import and convert the
* inherited environment.
*
* We require NO_SETENV (and let gitsetenv() call our msc_putenv).
* We require NO_SETENV (and let gitsetenv() call our mingw_putenv).
*/
#define getenv msc_getenv
#define putenv msc_putenv
#define unsetenv msc_putenv
#define mingw_getenv msc_getenv
#define mingw_putenv msc_putenv
char *msc_getenv(const char *name);
int msc_putenv(const char *name);
#ifndef NO_SETENV
#error "NO_SETENV is required for MSC startup code!"
#endif
#else
#define getenv mingw_getenv
#define putenv mingw_putenv
#define unsetenv mingw_putenv
char *mingw_getenv(const char *name);
#define getenv mingw_getenv
int mingw_putenv(const char *namevalue);
#define putenv mingw_putenv
#define unsetenv mingw_putenv
#endif
int mingw_putenv(const char *name);
int mingw_gethostname(char *host, int namelen);
#define gethostname mingw_gethostname
@@ -687,39 +666,18 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
extern CRITICAL_SECTION pinfo_cs;
/*
* A replacement of main() that adds win32 specific initialization.
* Git, like most portable C applications, implements a main() function. On
* Windows, this main() function would receive parameters encoded in the
* current locale, but Git for Windows would prefer UTF-8 encoded parameters.
*
* Note that the end of these macros are unterminated so that the
* brace group following the use of the macro is the body of the
* function.
* To make that happen, we still declare main() here, and then declare and
* implement wmain() (which is the Unicode variant of main()) and compile with
* -municode. This wmain() function reencodes the parameters from UTF-16 to
* UTF-8 format, sets up a couple of other things as required on Windows, and
* then hands off to the main() function.
*/
#if defined(_MSC_VER)
int msc_startup(int argc, wchar_t **w_argv, wchar_t **w_env);
extern int msc_main(int argc, const char **argv);
#define main(c,v) dummy_decl_msc_main(void); \
int wmain(int my_argc, \
wchar_t **my_w_argv, \
wchar_t **my_w_env) \
{ \
return msc_startup(my_argc, my_w_argv, my_w_env); \
} \
int msc_main(c, v)
#else
void mingw_startup(void);
#define main(c,v) dummy_decl_mingw_main(void); \
static int mingw_main(c,v); \
int main(int argc, const char **argv) \
{ \
mingw_startup(); \
return mingw_main(__argc, (void *)__argv); \
} \
static int mingw_main(c,v)
#endif
int wmain(int argc, const wchar_t **w_argv);
int main(int argc, const char **argv);
/*
* For debugging: if a problem occurs, say, in a Git process that is spawned

View File

@@ -1,7 +1,7 @@
The Steps to Build Git with VS2015 or VS2017 from the command line.
1. Install the "vcpkg" open source package manager and build essential
third-party libaries. The steps for this have been captured in a
third-party libraries. The steps for this have been captured in a
set of convenience scripts. These can be run from a stock Command
Prompt or from an SDK bash window:
@@ -45,7 +45,7 @@ Note that this will automatically add and commit the generated
.sln and .vcxproj files to the repo. You may want to drop this
commit before submitting a Pull Request....
Or maybe we should put the .sln/.vcxproj files in the .gitignores
Or maybe we should put the .sln/.vcxproj files in the .gitignore file
and not do this. I'm not sure.
================================================================

View File

@@ -398,12 +398,9 @@ ifeq ($(uname_S),Windows)
NO_MKDTEMP = YesPlease
NO_INTTYPES_H = YesPlease
# VS2015 with UCRT claims that snprintf and friends are C99 compliant,
# so we don't need this.
# so we don't need this:
#
# TODO If we want to support older compilers, we need to make this
# TODO conditional on the compiler version.
#
# SNPRINTF_RETURNS_BOGUS = YesPlease
# SNPRINTF_RETURNS_BOGUS = YesPlease
NO_SVN_TESTS = YesPlease
RUNTIME_PREFIX = YesPlease
HAVE_WPGMPTR = YesWeDo
@@ -587,6 +584,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
ETAGS_TARGET = ETAGS
NO_POSIX_GOODIES = UnfortunatelyYes
DEFAULT_HELP_FORMAT = html
BASIC_LDFLAGS += -municode
COMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
COMPAT_OBJS += compat/mingw.o compat/winansi.o \

View File

@@ -70,7 +70,7 @@ sub createProject {
}
my $defines = join(";", sort(@{$$build_structure{"$prefix${name}_DEFINES"}}));
my $includes= join(";", sort(map { s/^-I//; s/\//\\/g; File::Spec->file_name_is_absolute($_) ? $_ : "$rel_dir\\$_" } @{$$build_structure{"$prefix${name}_INCLUDES"}}));
my $cflags = join(" ", sort(map { s/^-[GLMOZ].*//; s/.* .*/"$&"/; $_; } @{$$build_structure{"$prefix${name}_CFLAGS"}}));
my $cflags = join(" ", sort(map { s/^-[GLMOWZ].*//; s/.* .*/"$&"/; $_; } @{$$build_structure{"$prefix${name}_CFLAGS"}}));
$cflags =~ s/</&lt;/g;
$cflags =~ s/>/&gt;/g;
@@ -179,10 +179,10 @@ sub createProject {
EOM
if ($target eq 'libgit') {
print F << "EOM";
<PreBuildEvent Condition="!Exists('$cdup\\compat\\vcbuild\\vcpkg') OR (!Exists('$cdup\\compat\\vcbuild\\vcpkg\\installed\\x64-windows\\include\\openssl\\ssl.h') AND !Exists('$cdup\\compat\\vcbuild\\vcpkg\\installed\\x86-windows\\include\\openssl\\ssl.h'))">
<PreBuildEvent Condition="!Exists('$cdup\\compat\\vcbuild\\vcpkg\\installed\\\$(VCPKGArch)\\include\\openssl\\ssl.h')">
<Message>Initialize VCPKG</Message>
<Command>del "$cdup\\compat\\vcbuild\\vcpkg"</Command>
<Command>call "$cdup\\compat\\vcbuild\\vcpkg_install.bat" </Command>
<Command>call "$cdup\\compat\\vcbuild\\vcpkg_install.bat"</Command>
</PreBuildEvent>
EOM
}

View File

@@ -3184,10 +3184,6 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len,
}
merge_commit = to_merge->item;
write_message(oid_to_hex(&merge_commit->object.oid), GIT_SHA1_HEXSZ,
git_path_merge_head(the_repository), 0);
write_message("no-ff", 5, git_path_merge_mode(the_repository), 0);
bases = get_merge_bases(head_commit, merge_commit);
if (bases && !oidcmp(&merge_commit->object.oid,
&bases->item->object.oid)) {
@@ -3196,6 +3192,10 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len,
goto leave_merge;
}
write_message(oid_to_hex(&merge_commit->object.oid), GIT_SHA1_HEXSZ,
git_path_merge_head(the_repository), 0);
write_message("no-ff", 5, git_path_merge_mode(the_repository), 0);
for (j = bases; j; j = j->next)
commit_list_insert(j->item, &reversed);
free_commit_list(bases);
@@ -3434,6 +3434,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
unlink(rebase_path_author_script());
unlink(rebase_path_stopped_sha());
unlink(rebase_path_amend());
unlink(git_path_merge_head(the_repository));
delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
}
if (item->command <= TODO_SQUASH) {
@@ -3790,6 +3791,7 @@ static int commit_staged_changes(struct replay_opts *opts,
opts, flags))
return error(_("could not commit staged changes."));
unlink(rebase_path_amend());
unlink(git_path_merge_head(the_repository));
if (final_fixup) {
unlink(rebase_path_fixup_msg());
unlink(rebase_path_squash_msg());

View File

@@ -268,6 +268,21 @@ void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2)
strbuf_setlen(sb, sb->len + sb2->len);
}
const char *strbuf_join_argv(struct strbuf *buf,
int argc, const char **argv, char delim)
{
if (!argc)
return buf->buf;
strbuf_addstr(buf, *argv);
while (--argc) {
strbuf_addch(buf, delim);
strbuf_addstr(buf, *(++argv));
}
return buf->buf;
}
void strbuf_addchars(struct strbuf *sb, int c, size_t n)
{
strbuf_grow(sb, n);

View File

@@ -287,6 +287,13 @@ static inline void strbuf_addstr(struct strbuf *sb, const char *s)
*/
extern void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2);
/**
* Join the arguments into a buffer. `delim` is put between every
* two arguments.
*/
const char *strbuf_join_argv(struct strbuf *buf, int argc,
const char **argv, char delim);
/**
* This function can be used to expand a format string containing
* placeholders. To that end, it parses the string and calls the specified

View File

@@ -169,6 +169,15 @@ appropriately before running "make".
implied by other options like --valgrind and
GIT_TEST_INSTALLED.
--no-bin-wrappers::
By default, the test suite uses the wrappers in
`../bin-wrappers/` to execute `git` and friends. With this option,
`../git` and friends are run directly. This is not recommended
in general, as the wrappers contain safeguards to ensure that no
files from an installed Git are used, but can speed up test runs
especially on platforms where running shell scripts is expensive
(most notably, Windows).
--root=<directory>::
Create "trash" directories used to store all temporary data during
testing under <directory>, instead of the t/ directory.

View File

@@ -486,7 +486,8 @@ test_expect_success MINGW 'redirect std handles' '
GIT_REDIRECT_STDERR="2>&1" \
git rev-parse --git-dir --verify refs/invalid &&
printf ".git\nfatal: Needed a single revision\n" >expect &&
test_cmp expect output.txt
sort <output.txt >output.sorted &&
test_cmp expect output.sorted
'
test_done

View File

@@ -148,7 +148,8 @@ test_trace () {
expect="$1"
shift
GIT_TRACE=1 test-tool run-command "$@" run-command true 2>&1 >/dev/null | \
sed -e 's/.* run_command: //' -e '/trace: .*/d' >actual &&
sed -e 's/.* run_command: //' -e '/trace: .*/d' \
-e '/RUNTIME_PREFIX requested/d' >actual &&
echo "$expect true" >expect &&
test_cmp expect actual
}

View File

@@ -351,4 +351,22 @@ test_expect_success 'autostash is saved on editor failure with conflict' '
test_cmp expected file0
'
test_expect_success 'autostash with dirty submodules' '
test_when_finished "git reset --hard && git checkout master" &&
git checkout -b with-submodule &&
git submodule add ./ sub &&
test_tick &&
git commit -m add-submodule &&
echo changed >sub/file0 &&
git rebase -i --autostash HEAD
'
test_expect_success 'branch is left alone when possible' '
git checkout -b unchanged-branch &&
echo changed >file0 &&
git rebase --autostash unchanged-branch &&
test changed = "$(cat file0)" &&
test unchanged-branch = "$(git rev-parse --abbrev-ref HEAD)"
'
test_done

View File

@@ -396,4 +396,20 @@ test_expect_success 'with --autosquash and --exec' '
grep "G: +G" actual
'
test_expect_success '--continue after resolving conflicts after a merge' '
git checkout -b already-has-g E &&
git cherry-pick E..G &&
test_commit H2 &&
git checkout -b conflicts-in-merge H &&
test_commit H2 H2.t conflicts H2-conflict &&
test_must_fail git rebase -r already-has-g &&
grep conflicts H2.t &&
echo resolved >H2.t &&
git add -u &&
git rebase --continue &&
test_must_fail git rev-parse --verify HEAD^2 &&
test_path_is_missing .git/MERGE_HEAD
'
test_done

View File

@@ -36,7 +36,7 @@ EOF
test_expect_success 'parents of stash' '
test $(git rev-parse stash^) = $(git rev-parse HEAD) &&
git diff stash^2..stash >output &&
test_cmp output expect
test_cmp expect output
'
test_expect_success 'applying bogus stash does nothing' '
@@ -210,9 +210,9 @@ test_expect_success 'stash branch' '
test refs/heads/stashbranch = $(git symbolic-ref HEAD) &&
test $(git rev-parse HEAD) = $(git rev-parse master^) &&
git diff --cached >output &&
test_cmp output expect &&
test_cmp expect output &&
git diff >output &&
test_cmp output expect1 &&
test_cmp expect1 output &&
git add file &&
git commit -m alternate\ second &&
git diff master..stashbranch >output &&
@@ -747,7 +747,7 @@ test_expect_success 'stash where working directory contains "HEAD" file' '
git diff-index --cached --quiet HEAD &&
test "$(git rev-parse stash^)" = "$(git rev-parse HEAD)" &&
git diff stash^..stash >output &&
test_cmp output expect
test_cmp expect output
'
test_expect_success 'store called with invalid commit' '

View File

@@ -15,26 +15,28 @@ test_expect_success 'setup' '
test_stat_and_patch () {
if test "<unset>" = "$1"
then
test_might_fail git config --unset stash.showStat
test_unconfig stash.showStat
else
test_config stash.showStat "$1"
fi &&
if test "<unset>" = "$2"
then
test_might_fail git config --unset stash.showPatch
test_unconfig stash.showPatch
else
test_config stash.showPatch "$2"
fi &&
shift &&
shift &&
shift 2 &&
echo 2 >file.t &&
git diff "$@" >expect &&
if test $# != 0
then
git diff "$@" >expect
fi &&
git stash &&
git stash show >actual &&
if test -z "$1"
if test $# = 0
then
test_must_be_empty actual
else

View File

@@ -259,6 +259,8 @@ do
test -z "$HARNESS_ACTIVE" && quiet=t; shift ;;
--with-dashes)
with_dashes=t; shift ;;
--no-bin-wrappers)
no_bin_wrappers=t; shift ;;
--no-color)
color=; shift ;;
--va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind)
@@ -1069,20 +1071,25 @@ then
PATH=$GIT_TEST_INSTALLED$PATH_SEP$GIT_BUILD_DIR/t/helper$PATH_SEP$PATH
GIT_EXEC_PATH=${GIT_TEST_EXEC_PATH:-$GIT_EXEC_PATH}
else # normal case, use ../bin-wrappers only unless $with_dashes:
git_bin_dir="$GIT_BUILD_DIR/bin-wrappers"
if ! test -x "$git_bin_dir/git"
if test -n "$no_bin_wrappers"
then
if test -z "$with_dashes"
then
say "$git_bin_dir/git is not executable; using GIT_EXEC_PATH"
fi
with_dashes=t
else
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"
fi
with_dashes=t
fi
PATH="$git_bin_dir$PATH_SEP$PATH"
fi
PATH="$git_bin_dir$PATH_SEP$PATH"
GIT_EXEC_PATH=$GIT_BUILD_DIR
if test -n "$with_dashes"
then
PATH="$GIT_BUILD_DIR$PATH_SEP$PATH"
PATH="$GIT_BUILD_DIR$PATH_SEP$GIT_BUILD_DIR/t/helper$PATH_SEP$PATH"
fi
fi
GIT_TEMPLATE_DIR="$GIT_BUILD_DIR"/templates/blt
@@ -1106,7 +1113,7 @@ test -d "$GIT_BUILD_DIR"/templates/blt || {
error "You haven't built things yet, have you?"
}
if ! test -x "$GIT_BUILD_DIR"/t/helper/test-tool
if ! test -x "$GIT_BUILD_DIR"/t/helper/test-tool$X
then
echo >&2 'You need to build test-tool:'
echo >&2 'Run "make t/helper/test-tool" in the source (toplevel) directory'

View File

@@ -1553,6 +1553,7 @@ void wt_status_get_state(struct wt_status_state *state,
struct object_id oid;
if (!stat(git_path_merge_head(the_repository), &st)) {
wt_status_check_rebase(NULL, state);
state->merge_in_progress = 1;
} else if (wt_status_check_rebase(NULL, state)) {
; /* all set */
@@ -1576,9 +1577,13 @@ static void wt_longstatus_print_state(struct wt_status *s,
struct wt_status_state *state)
{
const char *state_color = color(WT_STATUS_HEADER, s);
if (state->merge_in_progress)
if (state->merge_in_progress) {
if (state->rebase_interactive_in_progress) {
show_rebase_information(s, state, state_color);
fputs("\n", s->fp);
}
show_merge_in_progress(s, state, state_color);
else if (state->am_in_progress)
} else if (state->am_in_progress)
show_am_in_progress(s, state, state_color);
else if (state->rebase_in_progress || state->rebase_interactive_in_progress)
show_rebase_in_progress(s, state, state_color);