mirror of
https://github.com/git/git.git
synced 2026-01-17 14:21:57 +00:00
Merge pull request #1932 from dscho/prepare-for-2.20.0-rc0
Prepare for v2.20.0-rc0
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
256
builtin/rebase.c
256
builtin/rebase.c
@@ -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);
|
||||
|
||||
|
||||
540
builtin/stash.c
540
builtin/stash.c
File diff suppressed because it is too large
Load Diff
503
compat/mingw.c
503
compat/mingw.c
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
================================================================
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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/</</g;
|
||||
$cflags =~ s/>/>/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
|
||||
}
|
||||
|
||||
10
sequencer.c
10
sequencer.c
@@ -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());
|
||||
|
||||
15
strbuf.c
15
strbuf.c
@@ -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);
|
||||
|
||||
7
strbuf.h
7
strbuf.h
@@ -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
|
||||
|
||||
9
t/README
9
t/README
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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' '
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user