Merge branch 'master' of github.com:git/git

* 'master' of github.com:git/git: (34 commits)
  Git 2.42-rc2
  t4053: avoid writing to unopened pipe
  t4053: avoid race when killing background processes
  Git 2.42-rc1
  git maintenance: avoid console window in scheduled tasks on Windows
  win32: add a helper to run `git.exe` without a foreground window
  t9001: remove excessive GIT_SEND_EMAIL_NOTTY=1
  mv: handle lstat() failure correctly
  parse-options: disallow negating OPTION_SET_INT 0
  repack: free geometry struct
  send-email: avoid creating more than one Term::ReadLine object
  send-email: drop FakeTerm hack
  t0040: declare non-tab indentation to be okay in this script
  advice: handle "rebase" in error_resolve_conflict()
  A few more topics before -rc1
  mailmap: change primary address for Glen Choo
  gitignore: ignore clangd .cache directory
  docs: update when `git bisect visualize` uses `gitk`
  compat/mingw: implement a native locate_in_PATH()
  run-command: conditionally define locate_in_PATH()
  ...
This commit is contained in:
Jiang Xin 2023-08-16 07:24:56 +08:00
commit 62a26b36bd
42 changed files with 729 additions and 370 deletions

1
.gitignore vendored
View File

@ -222,6 +222,7 @@
/TAGS /TAGS
/cscope* /cscope*
/compile_commands.json /compile_commands.json
/.cache/
*.hcc *.hcc
*.obj *.obj
*.lib *.lib

View File

@ -80,6 +80,7 @@ Frank Lichtenheld <frank@lichtenheld.de> <flichtenheld@astaro.com>
Fredrik Kuivinen <frekui@gmail.com> <freku045@student.liu.se> Fredrik Kuivinen <frekui@gmail.com> <freku045@student.liu.se>
Frédéric Heitzmann <frederic.heitzmann@gmail.com> Frédéric Heitzmann <frederic.heitzmann@gmail.com>
Garry Dolley <gdolley@ucla.edu> <gdolley@arpnetworks.com> Garry Dolley <gdolley@ucla.edu> <gdolley@arpnetworks.com>
Glen Choo <glencbz@gmail.com> <chooglen@google.com>
Greg Price <price@mit.edu> <price@MIT.EDU> Greg Price <price@mit.edu> <price@MIT.EDU>
Greg Price <price@mit.edu> <price@ksplice.com> Greg Price <price@mit.edu> <price@ksplice.com>
Heiko Voigt <hvoigt@hvoigt.net> <git-list@hvoigt.net> Heiko Voigt <hvoigt@hvoigt.net> <git-list@hvoigt.net>

View File

@ -38,6 +38,12 @@ UI, Workflows & Features
being bisected or rebased. The message was reworded to say the being bisected or rebased. The message was reworded to say the
branch was "in use". branch was "in use".
* Tone down the warning on SHA-256 repositories being an experimental
curiosity. We do not have support for them to interoperate with
traditional SHA-1 repositories, but at this point, we do not plan
to make breaking changes to SHA-256 repositories and there is no
longer need for such a strongly phrased warning.
Performance, Internal Implementation, Development Support etc. Performance, Internal Implementation, Development Support etc.
@ -252,6 +258,36 @@ Fixes since v2.41
submodule.<name>.update configuration variable. submodule.<name>.update configuration variable.
(merge 7cebc5bd78 pv/doc-submodule-update-settings later to maint). (merge 7cebc5bd78 pv/doc-submodule-update-settings later to maint).
* Adjust to OpenSSL 3+, which deprecates its SHA-1 functions based on
its traditional API, by using its EVP API instead.
(merge bda9c12073 ew/hash-with-openssl-evp later to maint).
* Exclude "." from the set of characters to be removed from the
beginning and the end of the human-readable name.
(merge 1c04cb0744 bc/ident-dot-is-no-longer-crud-letter later to maint).
* "git bisect visualize" stopped running "gitk" on Git for Windows
when the command was reimplemented in C around Git 2.34 timeframe.
This has been corrected.
(merge fff1594fa7 ma/locate-in-path-for-windows later to maint).
* "git rebase -i" with a series of squash/fixup, when one of the
steps stopped in conflicts and ended up getting skipped, did not
handle the accumulated commit log messages, which has been
corrected.
(merge 6ce7afe163 pw/rebase-skip-commit-message-fix later to maint).
* Adjust to newer Term::ReadLine to prevent it from breaking
the interactive prompt code in send-email.
(merge c016726c2d jk/send-email-with-new-readline later to maint).
* Windows updates.
(merge 0050f8e401 ds/maintenance-on-windows-fix later to maint).
* Correct use of lstat() that assumed a failing call would not
clobber the statbuf.
(merge 72695d8214 st/mv-lstat-fix later to maint).
* Other code cleanup, docfix, build fix, etc. * Other code cleanup, docfix, build fix, etc.
(merge 51f9d2e563 sa/doc-ls-remote later to maint). (merge 51f9d2e563 sa/doc-ls-remote later to maint).
(merge c6d26a9dda jk/format-patch-message-id-unleak later to maint). (merge c6d26a9dda jk/format-patch-message-id-unleak later to maint).
@ -286,3 +322,8 @@ Fixes since v2.41
(merge c95ae3ff9c rs/describe-parseopt-fix later to maint). (merge c95ae3ff9c rs/describe-parseopt-fix later to maint).
(merge 36f76d2a25 rs/pack-objects-parseopt-fix later to maint). (merge 36f76d2a25 rs/pack-objects-parseopt-fix later to maint).
(merge 30c8c55cbf jc/tree-walk-drop-base-offset later to maint). (merge 30c8c55cbf jc/tree-walk-drop-base-offset later to maint).
(merge d089a06421 rs/bundle-parseopt-cleanup later to maint).
(merge 823839bda1 ew/sha256-gcrypt-leak-fixes later to maint).
(merge a5c01603b3 bc/ignore-clangd-cache later to maint).
(merge 12009a182b js/allow-t4000-to-be-indented-with-spaces later to maint).
(merge b3dcd24b8a jc/send-email-pre-process-fix later to maint).

View File

@ -204,9 +204,14 @@ as an alternative to `visualize`):
$ git bisect visualize $ git bisect visualize
------------ ------------
If the `DISPLAY` environment variable is not set, 'git log' is used Git detects a graphical environment through various environment variables:
instead. You can also give command-line options such as `-p` and `DISPLAY`, which is set in X Window System environments on Unix systems.
`--stat`. `SESSIONNAME`, which is set under Cygwin in interactive desktop sessions.
`MSYSTEM`, which is set under Msys2 and Git for Windows.
`SECURITYSESSIONID`, which may be set on macOS in interactive desktop sessions.
If none of these environment variables is set, 'git log' is used instead.
You can also give command-line options such as `-p` and `--stat`.
------------ ------------
$ git bisect visualize --stat $ git bisect visualize --stat

View File

@ -553,8 +553,8 @@ double-quotes and respecting backslash escapes. E.g., the value
If this variable is set, the default hash algorithm for new If this variable is set, the default hash algorithm for new
repositories will be set to this value. This value is repositories will be set to this value. This value is
ignored when cloning and the setting of the remote repository ignored when cloning and the setting of the remote repository
is always used. The default is "sha1". THIS VARIABLE IS is always used. The default is "sha1".
EXPERIMENTAL! See `--object-format` in linkgit:git-init[1]. See `--object-format` in linkgit:git-init[1].
Git Commits Git Commits
~~~~~~~~~~~ ~~~~~~~~~~~

View File

@ -1,6 +1,9 @@
THIS OPTION IS EXPERIMENTAL! SHA-256 support is experimental and still Note: At present, there is no interoperability between SHA-256
in an early stage. A SHA-256 repository will in general not be able to repositories and SHA-1 repositories.
share work with "regular" SHA-1 repositories. It should be assumed
that, e.g., Git internal file formats in relation to SHA-256 Historically, we warned that SHA-256 repositories may later need
repositories may change in backwards-incompatible ways. Only use backward incompatible changes when we introduce such interoperability
`--object-format=sha256` for testing purposes. features. Today, we only expect compatible changes. Furthermore, if such
changes prove to be necessary, it can be expected that SHA-256 repositories
created with today's Git will be usable by future versions of Git
without data loss.

View File

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
GVF=GIT-VERSION-FILE GVF=GIT-VERSION-FILE
DEF_VER=v2.42.0-rc0 DEF_VER=v2.42.0-rc2
LF=' LF='
' '

View File

@ -2779,6 +2779,13 @@ compat/nedmalloc/nedmalloc.sp compat/nedmalloc/nedmalloc.o: EXTRA_CPPFLAGS = \
compat/nedmalloc/nedmalloc.sp: SP_EXTRA_FLAGS += -Wno-non-pointer-null compat/nedmalloc/nedmalloc.sp: SP_EXTRA_FLAGS += -Wno-non-pointer-null
endif endif
headless-git.o: compat/win32/headless.c GIT-CFLAGS
$(QUIET_CC)$(CC) $(ALL_CFLAGS) $(COMPAT_CFLAGS) \
-fno-stack-protector -o $@ -c -Wall -Wwrite-strings $<
headless-git$X: headless-git.o git.res GIT-LDFLAGS
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -mwindows -o $@ $< git.res
git-%$X: %.o GIT-LDFLAGS $(GITLIBS) git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
@ -3216,6 +3223,12 @@ $(SP_OBJ): %.sp: %.c %.o
sparse: $(SP_OBJ) sparse: $(SP_OBJ)
EXCEPT_HDRS := $(GENERATED_H) unicode-width.h compat/% xdiff/% EXCEPT_HDRS := $(GENERATED_H) unicode-width.h compat/% xdiff/%
ifndef OPENSSL_SHA1
EXCEPT_HDRS += sha1/openssl.h
endif
ifndef OPENSSL_SHA256
EXCEPT_HDRS += sha256/openssl.h
endif
ifndef NETTLE_SHA256 ifndef NETTLE_SHA256
EXCEPT_HDRS += sha256/nettle.h EXCEPT_HDRS += sha256/nettle.h
endif endif
@ -3652,6 +3665,7 @@ clean: profile-clean coverage-clean cocciclean
$(RM) po/git.pot po/git-core.pot $(RM) po/git.pot po/git-core.pot
$(RM) git.res $(RM) git.res
$(RM) $(OBJECTS) $(RM) $(OBJECTS)
$(RM) headless-git.o
$(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(REFTABLE_TEST_LIB) $(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(REFTABLE_TEST_LIB)
$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS) $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS)
$(RM) $(TEST_PROGRAMS) $(RM) $(TEST_PROGRAMS)
@ -3680,6 +3694,7 @@ endif
$(RM) GIT-SCRIPT-DEFINES GIT-PERL-DEFINES GIT-PERL-HEADER GIT-PYTHON-VARS $(RM) GIT-SCRIPT-DEFINES GIT-PERL-DEFINES GIT-PERL-HEADER GIT-PYTHON-VARS
ifdef MSVC ifdef MSVC
$(RM) $(patsubst %.o,%.o.pdb,$(OBJECTS)) $(RM) $(patsubst %.o,%.o.pdb,$(OBJECTS))
$(RM) headless-git.o.pdb
$(RM) $(patsubst %.exe,%.pdb,$(OTHER_PROGRAMS)) $(RM) $(patsubst %.exe,%.pdb,$(OTHER_PROGRAMS))
$(RM) $(patsubst %.exe,%.iobj,$(OTHER_PROGRAMS)) $(RM) $(patsubst %.exe,%.iobj,$(OTHER_PROGRAMS))
$(RM) $(patsubst %.exe,%.ipdb,$(OTHER_PROGRAMS)) $(RM) $(patsubst %.exe,%.ipdb,$(OTHER_PROGRAMS))

View File

@ -191,9 +191,10 @@ int error_resolve_conflict(const char *me)
error(_("Pulling is not possible because you have unmerged files.")); error(_("Pulling is not possible because you have unmerged files."));
else if (!strcmp(me, "revert")) else if (!strcmp(me, "revert"))
error(_("Reverting is not possible because you have unmerged files.")); error(_("Reverting is not possible because you have unmerged files."));
else if (!strcmp(me, "rebase"))
error(_("Rebasing is not possible because you have unmerged files."));
else else
error(_("It is not possible to %s because you have unmerged files."), BUG("Unhandled conflict reason '%s'", me);
me);
if (advice_enabled(ADVICE_RESOLVE_CONFLICT)) if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
/* /*

View File

@ -68,42 +68,36 @@ static int parse_options_cmd_bundle(int argc,
} }
static int cmd_bundle_create(int argc, const char **argv, const char *prefix) { static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
int all_progress_implied = 1; struct strvec pack_opts = STRVEC_INIT;
int progress = isatty(STDERR_FILENO);
struct strvec pack_opts;
int version = -1; int version = -1;
int ret; int ret;
struct option options[] = { struct option options[] = {
OPT_SET_INT('q', "quiet", &progress, OPT_PASSTHRU_ARGV('q', "quiet", &pack_opts, NULL,
N_("do not show progress meter"), 0), N_("do not show progress meter"),
OPT_SET_INT(0, "progress", &progress, PARSE_OPT_NOARG),
N_("show progress meter"), 1), OPT_PASSTHRU_ARGV(0, "progress", &pack_opts, NULL,
OPT_SET_INT_F(0, "all-progress", &progress, N_("show progress meter"),
N_("historical; same as --progress"), 2, PARSE_OPT_NOARG),
PARSE_OPT_HIDDEN), OPT_PASSTHRU_ARGV(0, "all-progress", &pack_opts, NULL,
OPT_HIDDEN_BOOL(0, "all-progress-implied", N_("historical; same as --progress"),
&all_progress_implied, PARSE_OPT_NOARG | PARSE_OPT_HIDDEN),
N_("historical; does nothing")), OPT_PASSTHRU_ARGV(0, "all-progress-implied", &pack_opts, NULL,
N_("historical; does nothing"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN),
OPT_INTEGER(0, "version", &version, OPT_INTEGER(0, "version", &version,
N_("specify bundle format version")), N_("specify bundle format version")),
OPT_END() OPT_END()
}; };
char *bundle_file; char *bundle_file;
if (isatty(STDERR_FILENO))
strvec_push(&pack_opts, "--progress");
strvec_push(&pack_opts, "--all-progress-implied");
argc = parse_options_cmd_bundle(argc, argv, prefix, argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_create_usage, options, &bundle_file); builtin_bundle_create_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */ /* bundle internals use argv[1] as further parameters */
strvec_init(&pack_opts);
if (progress == 0)
strvec_push(&pack_opts, "--quiet");
else if (progress == 1)
strvec_push(&pack_opts, "--progress");
else if (progress == 2)
strvec_push(&pack_opts, "--all-progress");
if (progress && all_progress_implied)
strvec_push(&pack_opts, "--all-progress-implied");
if (!startup_info->have_repository) if (!startup_info->have_repository)
die(_("Need a repository to create a bundle.")); die(_("Need a repository to create a bundle."));
ret = !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts, version); ret = !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts, version);

View File

@ -2068,7 +2068,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
"</Settings>\n" "</Settings>\n"
"<Actions Context=\"Author\">\n" "<Actions Context=\"Author\">\n"
"<Exec>\n" "<Exec>\n"
"<Command>\"%s\\git.exe\"</Command>\n" "<Command>\"%s\\headless-git.exe\"</Command>\n"
"<Arguments>--exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n" "<Arguments>--exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n"
"</Exec>\n" "</Exec>\n"
"</Actions>\n" "</Actions>\n"

View File

@ -184,7 +184,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
int src_dir_nr = 0, src_dir_alloc = 0; int src_dir_nr = 0, src_dir_alloc = 0;
struct strbuf a_src_dir = STRBUF_INIT; struct strbuf a_src_dir = STRBUF_INIT;
enum update_mode *modes, dst_mode = 0; enum update_mode *modes, dst_mode = 0;
struct stat st; struct stat st, dest_st;
struct string_list src_for_dst = STRING_LIST_INIT_NODUP; struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
struct lock_file lock_file = LOCK_INIT; struct lock_file lock_file = LOCK_INIT;
struct cache_entry *ce; struct cache_entry *ce;
@ -304,7 +304,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
goto act_on_entry; goto act_on_entry;
} }
if (S_ISDIR(st.st_mode) if (S_ISDIR(st.st_mode)
&& lstat(dst, &st) == 0) { && lstat(dst, &dest_st) == 0) {
bad = _("cannot move directory over file"); bad = _("cannot move directory over file");
goto act_on_entry; goto act_on_entry;
} }

View File

@ -492,15 +492,13 @@ static struct packed_git *get_preferred_pack(struct pack_geometry *geometry)
return NULL; return NULL;
} }
static void clear_pack_geometry(struct pack_geometry *geometry) static void free_pack_geometry(struct pack_geometry *geometry)
{ {
if (!geometry) if (!geometry)
return; return;
free(geometry->pack); free(geometry->pack);
geometry->pack_nr = 0; free(geometry);
geometry->pack_alloc = 0;
geometry->split = 0;
} }
struct midx_snapshot_ref_data { struct midx_snapshot_ref_data {
@ -1228,7 +1226,7 @@ cleanup:
string_list_clear(&names, 1); string_list_clear(&names, 1);
string_list_clear(&existing_nonkept_packs, 0); string_list_clear(&existing_nonkept_packs, 0);
string_list_clear(&existing_kept_packs, 0); string_list_clear(&existing_kept_packs, 0);
clear_pack_geometry(geometry); free_pack_geometry(geometry);
return ret; return ret;
} }

View File

@ -1347,6 +1347,11 @@ static char *path_lookup(const char *cmd, int exe_only)
return prog; return prog;
} }
char *mingw_locate_in_PATH(const char *cmd)
{
return path_lookup(cmd, 0);
}
static const wchar_t *wcschrnul(const wchar_t *s, wchar_t c) static const wchar_t *wcschrnul(const wchar_t *s, wchar_t c)
{ {
while (*s && *s != c) while (*s && *s != c)

View File

@ -177,6 +177,9 @@ pid_t waitpid(pid_t pid, int *status, int options);
#define kill mingw_kill #define kill mingw_kill
int mingw_kill(pid_t pid, int sig); int mingw_kill(pid_t pid, int sig);
#define locate_in_PATH mingw_locate_in_PATH
char *mingw_locate_in_PATH(const char *cmd);
#ifndef NO_OPENSSL #ifndef NO_OPENSSL
#include <openssl/ssl.h> #include <openssl/ssl.h>
static inline int mingw_SSL_set_fd(SSL *ssl, int fd) static inline int mingw_SSL_set_fd(SSL *ssl, int fd)

115
compat/win32/headless.c Normal file
View File

@ -0,0 +1,115 @@
/*
* headless Git - run Git without opening a console window on Windows
*/
#define STRICT
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
/*
* If `dir` contains the path to a Git exec directory, extend `PATH` to
* include the corresponding `bin/` directory (which is where all those
* `.dll` files needed by `git.exe` are, on Windows).
*/
static int extend_path(wchar_t *dir, size_t dir_len)
{
const wchar_t *suffix = L"\\libexec\\git-core";
size_t suffix_len = wcslen(suffix);
wchar_t *env;
DWORD len;
if (dir_len < suffix_len)
return 0;
dir_len -= suffix_len;
if (memcmp(dir + dir_len, suffix, suffix_len * sizeof(wchar_t)))
return 0;
len = GetEnvironmentVariableW(L"PATH", NULL, 0);
if (!len)
return 0;
env = _alloca((dir_len + 5 + len) * sizeof(wchar_t));
wcsncpy(env, dir, dir_len);
wcscpy(env + dir_len, L"\\bin;");
if (!GetEnvironmentVariableW(L"PATH", env + dir_len + 5, len))
return 0;
SetEnvironmentVariableW(L"PATH", env);
return 1;
}
int WINAPI wWinMain(_In_ HINSTANCE instance,
_In_opt_ HINSTANCE previous_instance,
_In_ LPWSTR command_line, _In_ int show)
{
wchar_t git_command_line[32768];
size_t size = sizeof(git_command_line) / sizeof(wchar_t);
const wchar_t *needs_quotes = L"";
int slash = 0, i;
STARTUPINFO startup_info = {
.cb = sizeof(STARTUPINFO),
.dwFlags = STARTF_USESHOWWINDOW,
.wShowWindow = SW_HIDE,
};
PROCESS_INFORMATION process_info = { 0 };
DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT |
CREATE_NEW_CONSOLE | CREATE_NO_WINDOW;
DWORD exit_code;
/* First, determine the full path of argv[0] */
for (i = 0; _wpgmptr[i]; i++)
if (_wpgmptr[i] == L' ')
needs_quotes = L"\"";
else if (_wpgmptr[i] == L'\\')
slash = i;
if (slash >= size - 11)
return 127; /* Too long path */
/* If it is in Git's exec path, add the bin/ directory to the PATH */
extend_path(_wpgmptr, slash);
/* Then, add the full path of `git.exe` as argv[0] */
i = swprintf_s(git_command_line, size, L"%ls%.*ls\\git.exe%ls",
needs_quotes, slash, _wpgmptr, needs_quotes);
if (i < 0)
return 127; /* Too long path */
if (*command_line) {
/* Now, append the command-line arguments */
i = swprintf_s(git_command_line + i, size - i,
L" %ls", command_line);
if (i < 0)
return 127;
}
startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
if (!CreateProcess(NULL, /* infer argv[0] from the command line */
git_command_line, /* modified command line */
NULL, /* inherit process handles? */
NULL, /* inherit thread handles? */
FALSE, /* handles inheritable? */
creation_flags,
NULL, /* use this process' environment */
NULL, /* use this process' working directory */
&startup_info, &process_info))
return 129; /* could not start */
WaitForSingleObject(process_info.hProcess, INFINITE);
if (!GetExitCodeProcess(process_info.hProcess, &exit_code))
exit_code = 130; /* Could not determine exit code? */
CloseHandle(process_info.hProcess);
CloseHandle(process_info.hThread);
return (int)exit_code;
}

View File

@ -526,6 +526,8 @@ else
endif endif
X = .exe X = .exe
EXTRA_PROGRAMS += headless-git$X
compat/msvc.o: compat/msvc.c compat/mingw.c GIT-CFLAGS compat/msvc.o: compat/msvc.c compat/mingw.c GIT-CFLAGS
endif endif
ifeq ($(uname_S),Interix) ifeq ($(uname_S),Interix)
@ -705,6 +707,7 @@ ifeq ($(uname_S),MINGW)
COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \ COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \
-fstack-protector-strong -fstack-protector-strong
EXTLIBS += -lntdll EXTLIBS += -lntdll
EXTRA_PROGRAMS += headless-git$X
INSTALL = /bin/install INSTALL = /bin/install
INTERNAL_QSORT = YesPlease INTERNAL_QSORT = YesPlease
HAVE_LIBCHARSET_H = YesPlease HAVE_LIBCHARSET_H = YesPlease

View File

@ -738,6 +738,15 @@ if(WIN32)
else() else()
message(FATAL_ERROR "Unhandled compiler: ${CMAKE_C_COMPILER_ID}") message(FATAL_ERROR "Unhandled compiler: ${CMAKE_C_COMPILER_ID}")
endif() endif()
add_executable(headless-git ${CMAKE_SOURCE_DIR}/compat/win32/headless.c)
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
target_link_options(headless-git PUBLIC -municode -Wl,-subsystem,windows)
elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
target_link_options(headless-git PUBLIC /NOLOGO /ENTRY:wWinMainCRTStartup /SUBSYSTEM:WINDOWS)
else()
message(FATAL_ERROR "Unhandled compiler: ${CMAKE_C_COMPILER_ID}")
endif()
elseif(UNIX) elseif(UNIX)
target_link_libraries(common-main pthread rt) target_link_libraries(common-main pthread rt)
endif() endif()

View File

@ -76,7 +76,7 @@ sub createProject {
my $libs_release = "\n "; my $libs_release = "\n ";
my $libs_debug = "\n "; my $libs_debug = "\n ";
if (!$static_library) { if (!$static_library && $name ne 'headless-git') {
$libs_release = join(";", sort(grep /^(?!libgit\.lib|xdiff\/lib\.lib|vcs-svn\/lib\.lib|reftable\/libreftable\.lib)/, @{$$build_structure{"$prefix${name}_LIBS"}})); $libs_release = join(";", sort(grep /^(?!libgit\.lib|xdiff\/lib\.lib|vcs-svn\/lib\.lib|reftable\/libreftable\.lib)/, @{$$build_structure{"$prefix${name}_LIBS"}}));
$libs_debug = $libs_release; $libs_debug = $libs_release;
$libs_debug =~ s/zlib\.lib/zlibd\.lib/g; $libs_debug =~ s/zlib\.lib/zlibd\.lib/g;
@ -230,7 +230,7 @@ EOM
print F << "EOM"; print F << "EOM";
</ItemGroup> </ItemGroup>
EOM EOM
if (!$static_library || $target =~ 'vcs-svn' || $target =~ 'xdiff') { if ((!$static_library || $target =~ 'vcs-svn' || $target =~ 'xdiff') && !($name =~ /headless-git/)) {
my $uuid_libgit = $$build_structure{"LIBS_libgit_GUID"}; my $uuid_libgit = $$build_structure{"LIBS_libgit_GUID"};
my $uuid_libreftable = $$build_structure{"LIBS_reftable/libreftable_GUID"}; my $uuid_libreftable = $$build_structure{"LIBS_reftable/libreftable_GUID"};
my $uuid_xdiff_lib = $$build_structure{"LIBS_xdiff/lib_GUID"}; my $uuid_xdiff_lib = $$build_structure{"LIBS_xdiff/lib_GUID"};

View File

@ -371,6 +371,7 @@ sub handleLinkLine
# exit(1); # exit(1);
foreach (@objfiles) { foreach (@objfiles) {
my $sourcefile = $_; my $sourcefile = $_;
$sourcefile =~ s/^headless-git\.o$/compat\/win32\/headless.c/;
$sourcefile =~ s/\.o$/.c/; $sourcefile =~ s/\.o$/.c/;
push(@sources, $sourcefile); push(@sources, $sourcefile);
push(@cflags, @{$compile_options{"${sourcefile}_CFLAGS"}}); push(@cflags, @{$compile_options{"${sourcefile}_CFLAGS"}});

View File

@ -26,18 +26,6 @@ use Git::I18N;
Getopt::Long::Configure qw/ pass_through /; Getopt::Long::Configure qw/ pass_through /;
package FakeTerm;
sub new {
my ($class, $reason) = @_;
return bless \$reason, shift;
}
sub readline {
my $self = shift;
die "Cannot use readline on FakeTerm: $$self";
}
package main;
sub usage { sub usage {
print <<EOT; print <<EOT;
git send-email' [<options>] <file|directory> git send-email' [<options>] <file|directory>
@ -971,17 +959,19 @@ EOT3
do_edit(@files); do_edit(@files);
} }
sub term { {
my $term = eval { # Only instantiate one $term per program run, since some
# Term::ReadLine providers refuse to create a second instance.
my $term;
sub term {
require Term::ReadLine; require Term::ReadLine;
$ENV{"GIT_SEND_EMAIL_NOTTY"} if (!defined $term) {
? Term::ReadLine->new('git-send-email', \*STDIN, \*STDOUT) $term = $ENV{"GIT_SEND_EMAIL_NOTTY"}
: Term::ReadLine->new('git-send-email'); ? Term::ReadLine->new('git-send-email', \*STDIN, \*STDOUT)
}; : Term::ReadLine->new('git-send-email');
if ($@) { }
$term = FakeTerm->new("$@: going non-interactive"); return $term;
} }
return $term;
} }
sub ask { sub ask {

View File

@ -4,7 +4,11 @@
#if defined(SHA1_APPLE) #if defined(SHA1_APPLE)
#include <CommonCrypto/CommonDigest.h> #include <CommonCrypto/CommonDigest.h>
#elif defined(SHA1_OPENSSL) #elif defined(SHA1_OPENSSL)
#include <openssl/sha.h> # include <openssl/sha.h>
# if defined(OPENSSL_API_LEVEL) && OPENSSL_API_LEVEL >= 3
# define SHA1_NEEDS_CLONE_HELPER
# include "sha1/openssl.h"
# endif
#elif defined(SHA1_DC) #elif defined(SHA1_DC)
#include "sha1dc_git.h" #include "sha1dc_git.h"
#else /* SHA1_BLK */ #else /* SHA1_BLK */
@ -17,7 +21,11 @@
#define SHA256_NEEDS_CLONE_HELPER #define SHA256_NEEDS_CLONE_HELPER
#include "sha256/gcrypt.h" #include "sha256/gcrypt.h"
#elif defined(SHA256_OPENSSL) #elif defined(SHA256_OPENSSL)
#include <openssl/sha.h> # include <openssl/sha.h>
# if defined(OPENSSL_API_LEVEL) && OPENSSL_API_LEVEL >= 3
# define SHA256_NEEDS_CLONE_HELPER
# include "sha256/openssl.h"
# endif
#else #else
#include "sha256/block/sha256.h" #include "sha256/block/sha256.h"
#endif #endif
@ -41,6 +49,10 @@
#define git_SHA1_Update platform_SHA1_Update #define git_SHA1_Update platform_SHA1_Update
#define git_SHA1_Final platform_SHA1_Final #define git_SHA1_Final platform_SHA1_Final
#ifdef platform_SHA1_Clone
#define git_SHA1_Clone platform_SHA1_Clone
#endif
#ifndef platform_SHA256_CTX #ifndef platform_SHA256_CTX
#define platform_SHA256_CTX SHA256_CTX #define platform_SHA256_CTX SHA256_CTX
#define platform_SHA256_Init SHA256_Init #define platform_SHA256_Init SHA256_Init
@ -63,10 +75,12 @@
#define git_SHA1_Update git_SHA1_Update_Chunked #define git_SHA1_Update git_SHA1_Update_Chunked
#endif #endif
#ifndef SHA1_NEEDS_CLONE_HELPER
static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src) static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src)
{ {
memcpy(dst, src, sizeof(*dst)); memcpy(dst, src, sizeof(*dst));
} }
#endif
#ifndef SHA256_NEEDS_CLONE_HELPER #ifndef SHA256_NEEDS_CLONE_HELPER
static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src) static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src)

View File

@ -203,7 +203,6 @@ void reset_ident_date(void)
static int crud(unsigned char c) static int crud(unsigned char c)
{ {
return c <= 32 || return c <= 32 ||
c == '.' ||
c == ',' || c == ',' ||
c == ':' || c == ':' ||
c == ';' || c == ';' ||

View File

@ -480,6 +480,9 @@ static void parse_options_check(const struct option *opts)
opts->long_name)) opts->long_name))
optbug(opts, "uses feature " optbug(opts, "uses feature "
"not supported for dashless options"); "not supported for dashless options");
if (opts->type == OPTION_SET_INT && !opts->defval &&
opts->long_name && !(opts->flags & PARSE_OPT_NONEG))
optbug(opts, "OPTION_SET_INT 0 should not be negatable");
switch (opts->type) { switch (opts->type) {
case OPTION_COUNTUP: case OPTION_COUNTUP:
case OPTION_BIT: case OPTION_BIT:

View File

@ -170,6 +170,7 @@ int is_executable(const char *name)
return st.st_mode & S_IXUSR; return st.st_mode & S_IXUSR;
} }
#ifndef locate_in_PATH
/* /*
* Search $PATH for a command. This emulates the path search that * Search $PATH for a command. This emulates the path search that
* execvp would perform, without actually executing the command so it * execvp would perform, without actually executing the command so it
@ -218,6 +219,7 @@ static char *locate_in_PATH(const char *file)
strbuf_release(&buf); strbuf_release(&buf);
return NULL; return NULL;
} }
#endif
int exists_in_PATH(const char *command) int exists_in_PATH(const char *command)
{ {

View File

@ -5048,19 +5048,31 @@ static int commit_staged_changes(struct repository *r,
* We need to update the squash message to skip * We need to update the squash message to skip
* the latest commit message. * the latest commit message.
*/ */
int res = 0;
struct commit *commit; struct commit *commit;
const char *msg;
const char *path = rebase_path_squash_msg(); const char *path = rebase_path_squash_msg();
const char *encoding = get_commit_output_encoding(); const char *encoding = get_commit_output_encoding();
if (parse_head(r, &commit) || if (parse_head(r, &commit))
!(p = repo_logmsg_reencode(r, commit, NULL, encoding)) || return error(_("could not parse HEAD"));
write_message(p, strlen(p), path, 0)) {
repo_unuse_commit_buffer(r, commit, p); p = repo_logmsg_reencode(r, commit, NULL, encoding);
return error(_("could not write file: " if (!p) {
"'%s'"), path); res = error(_("could not parse commit %s"),
oid_to_hex(&commit->object.oid));
goto unuse_commit_buffer;
} }
repo_unuse_commit_buffer(r, find_commit_subject(p, &msg);
commit, p); if (write_message(msg, strlen(msg), path, 0)) {
res = error(_("could not write file: "
"'%s'"), path);
goto unuse_commit_buffer;
}
unuse_commit_buffer:
repo_unuse_commit_buffer(r, commit, p);
if (res)
return res;
} }
} }

49
sha1/openssl.h Normal file
View File

@ -0,0 +1,49 @@
/* wrappers for the EVP API of OpenSSL 3+ */
#ifndef SHA1_OPENSSL_H
#define SHA1_OPENSSL_H
#include <openssl/evp.h>
struct openssl_SHA1_CTX {
EVP_MD_CTX *ectx;
};
typedef struct openssl_SHA1_CTX openssl_SHA1_CTX;
static inline void openssl_SHA1_Init(struct openssl_SHA1_CTX *ctx)
{
const EVP_MD *type = EVP_sha1();
ctx->ectx = EVP_MD_CTX_new();
if (!ctx->ectx)
die("EVP_MD_CTX_new: out of memory");
EVP_DigestInit_ex(ctx->ectx, type, NULL);
}
static inline void openssl_SHA1_Update(struct openssl_SHA1_CTX *ctx,
const void *data,
size_t len)
{
EVP_DigestUpdate(ctx->ectx, data, len);
}
static inline void openssl_SHA1_Final(unsigned char *digest,
struct openssl_SHA1_CTX *ctx)
{
EVP_DigestFinal_ex(ctx->ectx, digest, NULL);
EVP_MD_CTX_free(ctx->ectx);
}
static inline void openssl_SHA1_Clone(struct openssl_SHA1_CTX *dst,
const struct openssl_SHA1_CTX *src)
{
EVP_MD_CTX_copy_ex(dst->ectx, src->ectx);
}
#define platform_SHA_CTX openssl_SHA1_CTX
#define platform_SHA1_Init openssl_SHA1_Init
#define platform_SHA1_Clone openssl_SHA1_Clone
#define platform_SHA1_Update openssl_SHA1_Update
#define platform_SHA1_Final openssl_SHA1_Final
#endif /* SHA1_OPENSSL_H */

View File

@ -7,22 +7,25 @@
typedef gcry_md_hd_t gcrypt_SHA256_CTX; typedef gcry_md_hd_t gcrypt_SHA256_CTX;
inline void gcrypt_SHA256_Init(gcrypt_SHA256_CTX *ctx) static inline void gcrypt_SHA256_Init(gcrypt_SHA256_CTX *ctx)
{ {
gcry_md_open(ctx, GCRY_MD_SHA256, 0); gcry_error_t err = gcry_md_open(ctx, GCRY_MD_SHA256, 0);
if (err)
die("gcry_md_open: %s", gcry_strerror(err));
} }
inline void gcrypt_SHA256_Update(gcrypt_SHA256_CTX *ctx, const void *data, size_t len) static inline void gcrypt_SHA256_Update(gcrypt_SHA256_CTX *ctx, const void *data, size_t len)
{ {
gcry_md_write(*ctx, data, len); gcry_md_write(*ctx, data, len);
} }
inline void gcrypt_SHA256_Final(unsigned char *digest, gcrypt_SHA256_CTX *ctx) static inline void gcrypt_SHA256_Final(unsigned char *digest, gcrypt_SHA256_CTX *ctx)
{ {
memcpy(digest, gcry_md_read(*ctx, GCRY_MD_SHA256), SHA256_DIGEST_SIZE); memcpy(digest, gcry_md_read(*ctx, GCRY_MD_SHA256), SHA256_DIGEST_SIZE);
gcry_md_close(*ctx);
} }
inline void gcrypt_SHA256_Clone(gcrypt_SHA256_CTX *dst, const gcrypt_SHA256_CTX *src) static inline void gcrypt_SHA256_Clone(gcrypt_SHA256_CTX *dst, const gcrypt_SHA256_CTX *src)
{ {
gcry_md_copy(dst, *src); gcry_md_copy(dst, *src);
} }

49
sha256/openssl.h Normal file
View File

@ -0,0 +1,49 @@
/* wrappers for the EVP API of OpenSSL 3+ */
#ifndef SHA256_OPENSSL_H
#define SHA256_OPENSSL_H
#include <openssl/evp.h>
struct openssl_SHA256_CTX {
EVP_MD_CTX *ectx;
};
typedef struct openssl_SHA256_CTX openssl_SHA256_CTX;
static inline void openssl_SHA256_Init(struct openssl_SHA256_CTX *ctx)
{
const EVP_MD *type = EVP_sha256();
ctx->ectx = EVP_MD_CTX_new();
if (!ctx->ectx)
die("EVP_MD_CTX_new: out of memory");
EVP_DigestInit_ex(ctx->ectx, type, NULL);
}
static inline void openssl_SHA256_Update(struct openssl_SHA256_CTX *ctx,
const void *data,
size_t len)
{
EVP_DigestUpdate(ctx->ectx, data, len);
}
static inline void openssl_SHA256_Final(unsigned char *digest,
struct openssl_SHA256_CTX *ctx)
{
EVP_DigestFinal_ex(ctx->ectx, digest, NULL);
EVP_MD_CTX_free(ctx->ectx);
}
static inline void openssl_SHA256_Clone(struct openssl_SHA256_CTX *dst,
const struct openssl_SHA256_CTX *src)
{
EVP_MD_CTX_copy_ex(dst->ectx, src->ectx);
}
#define platform_SHA256_CTX openssl_SHA256_CTX
#define platform_SHA256_Init openssl_SHA256_Init
#define platform_SHA256_Clone openssl_SHA256_Clone
#define platform_SHA256_Update openssl_SHA256_Update
#define platform_SHA256_Final openssl_SHA256_Final
#endif /* SHA256_OPENSSL_H */

1
t/.gitattributes vendored
View File

@ -22,3 +22,4 @@ t[0-9][0-9][0-9][0-9]/* -whitespace
/t7500/* eol=lf /t7500/* eol=lf
/t8005/*.txt eol=lf /t8005/*.txt eol=lf
/t9*/*.dump eol=lf /t9*/*.dump eol=lf
/t0040*.sh whitespace=-indent-with-non-tab

View File

@ -14,24 +14,37 @@ graph_git_two_modes() {
test_cmp expect output test_cmp expect output
} }
# graph_git_behavior <name> <directory> <branch> <compare>
#
# Ensures that a handful of traversal operations produce the same
# results with and without the commit-graph in use.
#
# NOTE: it is a bug to call this function with <directory> containing
# any characters in $IFS.
graph_git_behavior() { graph_git_behavior() {
MSG=$1 MSG=$1
DIR=$2 DIR=$2
BRANCH=$3 BRANCH=$3
COMPARE=$4 COMPARE=$4
test_expect_success "check normal git operations: $MSG" ' test_expect_success "check normal git operations: $MSG" '
cd "$TRASH_DIRECTORY/$DIR" && graph_git_two_modes "${DIR:+-C $DIR} log --oneline $BRANCH" &&
graph_git_two_modes "log --oneline $BRANCH" && graph_git_two_modes "${DIR:+-C $DIR} log --topo-order $BRANCH" &&
graph_git_two_modes "log --topo-order $BRANCH" && graph_git_two_modes "${DIR:+-C $DIR} log --graph $COMPARE..$BRANCH" &&
graph_git_two_modes "log --graph $COMPARE..$BRANCH" && graph_git_two_modes "${DIR:+-C $DIR} branch -vv" &&
graph_git_two_modes "branch -vv" && graph_git_two_modes "${DIR:+-C $DIR} merge-base -a $BRANCH $COMPARE"
graph_git_two_modes "merge-base -a $BRANCH $COMPARE"
' '
} }
graph_read_expect() { graph_read_expect() {
OPTIONAL="" OPTIONAL=""
NUM_CHUNKS=3 NUM_CHUNKS=3
DIR="."
if test "$1" = -C
then
shift
DIR="$1"
shift
fi
if test -n "$2" if test -n "$2"
then then
OPTIONAL=" $2" OPTIONAL=" $2"
@ -47,12 +60,15 @@ graph_read_expect() {
then then
OPTIONS=" read_generation_data" OPTIONS=" read_generation_data"
fi fi
cat >expect <<- EOF cat >"$DIR/expect" <<-EOF
header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0 header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
num_commits: $1 num_commits: $1
chunks: oid_fanout oid_lookup commit_metadata$OPTIONAL chunks: oid_fanout oid_lookup commit_metadata$OPTIONAL
options:$OPTIONS options:$OPTIONS
EOF EOF
test-tool read-graph >output && (
test_cmp expect output cd "$DIR" &&
test-tool read-graph >output &&
test_cmp expect output
)
} }

View File

@ -115,15 +115,23 @@ test_expect_success '--skip after failed fixup cleans commit message' '
test_when_finished "test_might_fail git rebase --abort" && test_when_finished "test_might_fail git rebase --abort" &&
git checkout -b with-conflicting-fixup && git checkout -b with-conflicting-fixup &&
test_commit wants-fixup && test_commit wants-fixup &&
test_commit "fixup! wants-fixup" wants-fixup.t 1 wants-fixup-1 && test_commit "fixup 1" wants-fixup.t 1 wants-fixup-1 &&
test_commit "fixup! wants-fixup" wants-fixup.t 2 wants-fixup-2 && test_commit "fixup 2" wants-fixup.t 2 wants-fixup-2 &&
test_commit "fixup! wants-fixup" wants-fixup.t 3 wants-fixup-3 && test_commit "fixup 3" wants-fixup.t 3 wants-fixup-3 &&
test_must_fail env FAKE_LINES="1 fixup 2 squash 4" \ test_must_fail env FAKE_LINES="1 fixup 2 squash 4" \
git rebase -i HEAD~4 && git rebase -i HEAD~4 &&
: now there is a conflict, and comments in the commit message && : now there is a conflict, and comments in the commit message &&
git show HEAD >out && test_commit_message HEAD <<-\EOF &&
grep "fixup! wants-fixup" out && # This is a combination of 2 commits.
# This is the 1st commit message:
wants-fixup
# The commit message #2 will be skipped:
# fixup 1
EOF
: skip and continue && : skip and continue &&
echo "cp \"\$1\" .git/copy.txt" | write_script copy-editor.sh && echo "cp \"\$1\" .git/copy.txt" | write_script copy-editor.sh &&
@ -133,33 +141,49 @@ test_expect_success '--skip after failed fixup cleans commit message' '
test_path_is_missing .git/copy.txt && test_path_is_missing .git/copy.txt &&
: now the comments in the commit message should have been cleaned up && : now the comments in the commit message should have been cleaned up &&
git show HEAD >out && test_commit_message HEAD -m wants-fixup &&
! grep "fixup! wants-fixup" out &&
: now, let us ensure that "squash" is handled correctly && : now, let us ensure that "squash" is handled correctly &&
git reset --hard wants-fixup-3 && git reset --hard wants-fixup-3 &&
test_must_fail env FAKE_LINES="1 squash 4 squash 2 squash 4" \ test_must_fail env FAKE_LINES="1 squash 2 squash 1 squash 3 squash 1" \
git rebase -i HEAD~4 && git rebase -i HEAD~4 &&
: the first squash failed, but there are two more in the chain && : the second squash failed, but there are two more in the chain &&
(test_set_editor "$PWD/copy-editor.sh" && (test_set_editor "$PWD/copy-editor.sh" &&
test_must_fail git rebase --skip) && test_must_fail git rebase --skip) &&
: not the final squash, no need to edit the commit message && : not the final squash, no need to edit the commit message &&
test_path_is_missing .git/copy.txt && test_path_is_missing .git/copy.txt &&
: The first squash was skipped, therefore: && : The first and third squashes succeeded, therefore: &&
git show HEAD >out && test_commit_message HEAD <<-\EOF &&
test_i18ngrep "# This is a combination of 2 commits" out && # This is a combination of 3 commits.
test_i18ngrep "# This is the commit message #2:" out && # This is the 1st commit message:
wants-fixup
# This is the commit message #2:
fixup 1
# This is the commit message #3:
fixup 2
EOF
(test_set_editor "$PWD/copy-editor.sh" && git rebase --skip) && (test_set_editor "$PWD/copy-editor.sh" && git rebase --skip) &&
git show HEAD >out && test_commit_message HEAD <<-\EOF &&
test_i18ngrep ! "# This is a combination" out && wants-fixup
fixup 1
fixup 2
EOF
: Final squash failed, but there was still a squash && : Final squash failed, but there was still a squash &&
test_i18ngrep "# This is a combination of 2 commits" .git/copy.txt && head -n1 .git/copy.txt >first-line &&
test_i18ngrep "# This is the commit message #2:" .git/copy.txt test_i18ngrep "# This is a combination of 3 commits" first-line &&
test_i18ngrep "# This is the commit message #3:" .git/copy.txt
' '
test_expect_success 'setup rerere database' ' test_expect_success 'setup rerere database' '

View File

@ -21,21 +21,6 @@ TEST_PASSES_SANITIZE_LEAK=true
EMPTY="" EMPTY=""
# test_commit_message <rev> -m <msg>
# test_commit_message <rev> <path>
# Verify that the commit message of <rev> matches
# <msg> or the content of <path>.
test_commit_message () {
git show --no-patch --pretty=format:%B "$1" >actual &&
case "$2" in
-m)
echo "$3" >expect &&
test_cmp expect actual ;;
*)
test_cmp "$2" actual ;;
esac
}
get_author () { get_author () {
rev="$1" && rev="$1" &&
git log -1 --pretty=format:"%an %ae %at" "$rev" git log -1 --pretty=format:"%an %ae %at" "$rev"

View File

@ -232,10 +232,6 @@ test_expect_success 'diff --no-index refuses to diff stdin and a directory' '
test_expect_success PIPE 'diff --no-index refuses to diff a named pipe and a directory' ' test_expect_success PIPE 'diff --no-index refuses to diff a named pipe and a directory' '
test_when_finished "rm -f pipe" && test_when_finished "rm -f pipe" &&
mkfifo pipe && mkfifo pipe &&
{
(>pipe) &
} &&
test_when_finished "kill $!" &&
test_must_fail git diff --no-index -- pipe a 2>err && test_must_fail git diff --no-index -- pipe a 2>err &&
grep "fatal: cannot compare a named pipe to a directory" err grep "fatal: cannot compare a named pipe to a directory" err
' '
@ -248,11 +244,11 @@ test_expect_success PIPE,SYMLINKS 'diff --no-index reads from pipes' '
{ {
(test_write_lines a b c >old) & (test_write_lines a b c >old) &
} && } &&
test_when_finished "! kill $!" && test_when_finished "kill $! || :" &&
{ {
(test_write_lines a x c >new) & (test_write_lines a x c >new) &
} && } &&
test_when_finished "! kill $!" && test_when_finished "kill $! || :" &&
cat >expect <<-EOF && cat >expect <<-EOF &&
diff --git a/old b/new-link diff --git a/old b/new-link

View File

@ -466,7 +466,7 @@ test_expect_success 'gitmailmap(5) example output: example #1' '
Author Jane Doe <jane@laptop.(none)> maps to Jane Doe <jane@laptop.(none)> Author Jane Doe <jane@laptop.(none)> maps to Jane Doe <jane@laptop.(none)>
Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com> Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
Author Jane D <jane@desktop.(none)> maps to Jane Doe <jane@desktop.(none)> Author Jane D. <jane@desktop.(none)> maps to Jane Doe <jane@desktop.(none)>
Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com> Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
EOF EOF
git -C doc log --reverse --pretty=format:"Author %an <%ae> maps to %aN <%aE>%nCommitter %cn <%ce> maps to %cN <%cE>%n" >actual && git -C doc log --reverse --pretty=format:"Author %an <%ae> maps to %aN <%aE>%nCommitter %cn <%ce> maps to %cN <%cE>%n" >actual &&
@ -494,7 +494,7 @@ test_expect_success 'gitmailmap(5) example output: example #2' '
Author Jane Doe <jane@laptop.(none)> maps to Jane Doe <jane@example.com> Author Jane Doe <jane@laptop.(none)> maps to Jane Doe <jane@example.com>
Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com> Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
Author Jane D <jane@desktop.(none)> maps to Jane Doe <jane@example.com> Author Jane D. <jane@desktop.(none)> maps to Jane Doe <jane@example.com>
Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com> Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
EOF EOF
git -C doc log --reverse --pretty=format:"Author %an <%ae> maps to %aN <%aE>%nCommitter %cn <%ce> maps to %cN <%cE>%n" >actual && git -C doc log --reverse --pretty=format:"Author %an <%ae> maps to %aN <%aE>%nCommitter %cn <%ce> maps to %cN <%cE>%n" >actual &&

View File

@ -24,12 +24,10 @@ test_expect_success 'usage shown with an error on unknown sub-command' '
test_cmp expect actual test_cmp expect actual
' '
objdir=".git/objects"
test_expect_success 'setup full repo' ' test_expect_success 'setup full repo' '
mkdir full && git init full
cd "$TRASH_DIRECTORY/full" &&
git init &&
git config core.commitGraph true &&
objdir=".git/objects"
' '
test_expect_success POSIXPERM 'tweak umask for modebit tests' ' test_expect_success POSIXPERM 'tweak umask for modebit tests' '
@ -37,31 +35,28 @@ test_expect_success POSIXPERM 'tweak umask for modebit tests' '
' '
test_expect_success 'verify graph with no graph file' ' test_expect_success 'verify graph with no graph file' '
cd "$TRASH_DIRECTORY/full" && git -C full commit-graph verify
git commit-graph verify
' '
test_expect_success 'write graph with no packs' ' test_expect_success 'write graph with no packs' '
cd "$TRASH_DIRECTORY/full" && git -C full commit-graph write --object-dir $objdir &&
git commit-graph write --object-dir $objdir && test_path_is_missing full/$objdir/info/commit-graph
test_path_is_missing $objdir/info/commit-graph
' '
test_expect_success 'exit with correct error on bad input to --stdin-packs' ' test_expect_success 'exit with correct error on bad input to --stdin-packs' '
cd "$TRASH_DIRECTORY/full" &&
echo doesnotexist >in && echo doesnotexist >in &&
test_expect_code 1 git commit-graph write --stdin-packs <in 2>stderr && test_expect_code 1 git -C full commit-graph write --stdin-packs \
<in 2>stderr &&
test_i18ngrep "error adding pack" stderr test_i18ngrep "error adding pack" stderr
' '
test_expect_success 'create commits and repack' ' test_expect_success 'create commits and repack' '
cd "$TRASH_DIRECTORY/full" &&
for i in $(test_seq 3) for i in $(test_seq 3)
do do
test_commit $i && test_commit -C full $i &&
git branch commits/$i || return 1 git -C full branch commits/$i || return 1
done && done &&
git repack git -C full repack
' '
. "$TEST_DIRECTORY"/lib-commit-graph.sh . "$TEST_DIRECTORY"/lib-commit-graph.sh
@ -69,117 +64,106 @@ test_expect_success 'create commits and repack' '
graph_git_behavior 'no graph' full commits/3 commits/1 graph_git_behavior 'no graph' full commits/3 commits/1
test_expect_success 'exit with correct error on bad input to --stdin-commits' ' test_expect_success 'exit with correct error on bad input to --stdin-commits' '
cd "$TRASH_DIRECTORY/full" &&
# invalid, non-hex OID # invalid, non-hex OID
echo HEAD >in && echo HEAD | test_expect_code 1 git -C full commit-graph write \
test_expect_code 1 git commit-graph write --stdin-commits <in 2>stderr && --stdin-commits 2>stderr &&
test_i18ngrep "unexpected non-hex object ID: HEAD" stderr && test_i18ngrep "unexpected non-hex object ID: HEAD" stderr &&
# non-existent OID # non-existent OID
echo $ZERO_OID >in && echo $ZERO_OID | test_expect_code 1 git -C full commit-graph write \
test_expect_code 1 git commit-graph write --stdin-commits <in 2>stderr && --stdin-commits 2>stderr &&
test_i18ngrep "invalid object" stderr && test_i18ngrep "invalid object" stderr &&
# valid commit and tree OID # valid commit and tree OID
git rev-parse HEAD HEAD^{tree} >in && git -C full rev-parse HEAD HEAD^{tree} >in &&
git commit-graph write --stdin-commits <in && git -C full commit-graph write --stdin-commits <in &&
graph_read_expect 3 generation_data graph_read_expect -C full 3 generation_data
' '
test_expect_success 'write graph' ' test_expect_success 'write graph' '
cd "$TRASH_DIRECTORY/full" && git -C full commit-graph write &&
git commit-graph write && test_path_is_file full/$objdir/info/commit-graph &&
test_path_is_file $objdir/info/commit-graph && graph_read_expect -C full 3 generation_data
graph_read_expect "3" generation_data
' '
test_expect_success POSIXPERM 'write graph has correct permissions' ' test_expect_success POSIXPERM 'write graph has correct permissions' '
test_path_is_file $objdir/info/commit-graph && test_path_is_file full/$objdir/info/commit-graph &&
echo "-r--r--r--" >expect && echo "-r--r--r--" >expect &&
test_modebits $objdir/info/commit-graph >actual && test_modebits full/$objdir/info/commit-graph >actual &&
test_cmp expect actual test_cmp expect actual
' '
graph_git_behavior 'graph exists' full commits/3 commits/1 graph_git_behavior 'graph exists' full commits/3 commits/1
test_expect_success 'Add more commits' ' test_expect_success 'Add more commits' '
cd "$TRASH_DIRECTORY/full" && git -C full reset --hard commits/1 &&
git reset --hard commits/1 &&
for i in $(test_seq 4 5) for i in $(test_seq 4 5)
do do
test_commit $i && test_commit -C full $i &&
git branch commits/$i || return 1 git -C full branch commits/$i || return 1
done && done &&
git reset --hard commits/2 && git -C full reset --hard commits/2 &&
for i in $(test_seq 6 7) for i in $(test_seq 6 7)
do do
test_commit $i && test_commit -C full $i &&
git branch commits/$i || return 1 git -C full branch commits/$i || return 1
done && done &&
git reset --hard commits/2 && git -C full reset --hard commits/2 &&
git merge commits/4 && git -C full merge commits/4 &&
git branch merge/1 && git -C full branch merge/1 &&
git reset --hard commits/4 && git -C full reset --hard commits/4 &&
git merge commits/6 && git -C full merge commits/6 &&
git branch merge/2 && git -C full branch merge/2 &&
git reset --hard commits/3 && git -C full reset --hard commits/3 &&
git merge commits/5 commits/7 && git -C full merge commits/5 commits/7 &&
git branch merge/3 && git -C full branch merge/3 &&
git repack git -C full repack
' '
test_expect_success 'commit-graph write progress off for redirected stderr' ' test_expect_success 'commit-graph write progress off for redirected stderr' '
cd "$TRASH_DIRECTORY/full" && git -C full commit-graph write 2>err &&
git commit-graph write 2>err &&
test_must_be_empty err test_must_be_empty err
' '
test_expect_success 'commit-graph write force progress on for stderr' ' test_expect_success 'commit-graph write force progress on for stderr' '
cd "$TRASH_DIRECTORY/full" && GIT_PROGRESS_DELAY=0 git -C full commit-graph write --progress 2>err &&
GIT_PROGRESS_DELAY=0 git commit-graph write --progress 2>err &&
test_file_not_empty err test_file_not_empty err
' '
test_expect_success 'commit-graph write with the --no-progress option' ' test_expect_success 'commit-graph write with the --no-progress option' '
cd "$TRASH_DIRECTORY/full" && git -C full commit-graph write --no-progress 2>err &&
git commit-graph write --no-progress 2>err &&
test_must_be_empty err test_must_be_empty err
' '
test_expect_success 'commit-graph write --stdin-commits progress off for redirected stderr' ' test_expect_success 'commit-graph write --stdin-commits progress off for redirected stderr' '
cd "$TRASH_DIRECTORY/full" && git -C full rev-parse commits/5 >in &&
git rev-parse commits/5 >in && git -C full commit-graph write --stdin-commits <in 2>err &&
git commit-graph write --stdin-commits <in 2>err &&
test_must_be_empty err test_must_be_empty err
' '
test_expect_success 'commit-graph write --stdin-commits force progress on for stderr' ' test_expect_success 'commit-graph write --stdin-commits force progress on for stderr' '
cd "$TRASH_DIRECTORY/full" && git -C full rev-parse commits/5 >in &&
git rev-parse commits/5 >in && GIT_PROGRESS_DELAY=0 git -C full commit-graph write --stdin-commits \
GIT_PROGRESS_DELAY=0 git commit-graph write --stdin-commits --progress <in 2>err && --progress <in 2>err &&
test_i18ngrep "Collecting commits from input" err test_i18ngrep "Collecting commits from input" err
' '
test_expect_success 'commit-graph write --stdin-commits with the --no-progress option' ' test_expect_success 'commit-graph write --stdin-commits with the --no-progress option' '
cd "$TRASH_DIRECTORY/full" && git -C full rev-parse commits/5 >in &&
git rev-parse commits/5 >in && git -C full commit-graph write --stdin-commits --no-progress <in 2>err &&
git commit-graph write --stdin-commits --no-progress <in 2>err &&
test_must_be_empty err test_must_be_empty err
' '
test_expect_success 'commit-graph verify progress off for redirected stderr' ' test_expect_success 'commit-graph verify progress off for redirected stderr' '
cd "$TRASH_DIRECTORY/full" && git -C full commit-graph verify 2>err &&
git commit-graph verify 2>err &&
test_must_be_empty err test_must_be_empty err
' '
test_expect_success 'commit-graph verify force progress on for stderr' ' test_expect_success 'commit-graph verify force progress on for stderr' '
cd "$TRASH_DIRECTORY/full" && GIT_PROGRESS_DELAY=0 git -C full commit-graph verify --progress 2>err &&
GIT_PROGRESS_DELAY=0 git commit-graph verify --progress 2>err &&
test_file_not_empty err test_file_not_empty err
' '
test_expect_success 'commit-graph verify with the --no-progress option' ' test_expect_success 'commit-graph verify with the --no-progress option' '
cd "$TRASH_DIRECTORY/full" && git -C full commit-graph verify --no-progress 2>err &&
git commit-graph verify --no-progress 2>err &&
test_must_be_empty err test_must_be_empty err
' '
@ -194,10 +178,9 @@ test_expect_success 'commit-graph verify with the --no-progress option' '
# 1 # 1
test_expect_success 'write graph with merges' ' test_expect_success 'write graph with merges' '
cd "$TRASH_DIRECTORY/full" && git -C full commit-graph write &&
git commit-graph write && test_path_is_file full/$objdir/info/commit-graph &&
test_path_is_file $objdir/info/commit-graph && graph_read_expect -C full 10 "generation_data extra_edges"
graph_read_expect "10" "generation_data extra_edges"
' '
graph_git_behavior 'merge 1 vs 2' full merge/1 merge/2 graph_git_behavior 'merge 1 vs 2' full merge/1 merge/2
@ -205,12 +188,11 @@ graph_git_behavior 'merge 1 vs 3' full merge/1 merge/3
graph_git_behavior 'merge 2 vs 3' full merge/2 merge/3 graph_git_behavior 'merge 2 vs 3' full merge/2 merge/3
test_expect_success 'Add one more commit' ' test_expect_success 'Add one more commit' '
cd "$TRASH_DIRECTORY/full" && test_commit -C full 8 &&
test_commit 8 && git -C full branch commits/8 &&
git branch commits/8 && ls full/$objdir/pack | grep idx >existing-idx &&
ls $objdir/pack | grep idx >existing-idx && git -C full repack &&
git repack && ls full/$objdir/pack| grep idx | grep -v -f existing-idx >new-idx
ls $objdir/pack| grep idx | grep -v -f existing-idx >new-idx
' '
# Current graph structure: # Current graph structure:
@ -229,114 +211,101 @@ graph_git_behavior 'mixed mode, commit 8 vs merge 1' full commits/8 merge/1
graph_git_behavior 'mixed mode, commit 8 vs merge 2' full commits/8 merge/2 graph_git_behavior 'mixed mode, commit 8 vs merge 2' full commits/8 merge/2
test_expect_success 'write graph with new commit' ' test_expect_success 'write graph with new commit' '
cd "$TRASH_DIRECTORY/full" && git -C full commit-graph write &&
git commit-graph write && test_path_is_file full/$objdir/info/commit-graph &&
test_path_is_file $objdir/info/commit-graph && graph_read_expect -C full 11 "generation_data extra_edges"
graph_read_expect "11" "generation_data extra_edges"
' '
graph_git_behavior 'full graph, commit 8 vs merge 1' full commits/8 merge/1 graph_git_behavior 'full graph, commit 8 vs merge 1' full commits/8 merge/1
graph_git_behavior 'full graph, commit 8 vs merge 2' full commits/8 merge/2 graph_git_behavior 'full graph, commit 8 vs merge 2' full commits/8 merge/2
test_expect_success 'write graph with nothing new' ' test_expect_success 'write graph with nothing new' '
cd "$TRASH_DIRECTORY/full" && git -C full commit-graph write &&
git commit-graph write && test_path_is_file full/$objdir/info/commit-graph &&
test_path_is_file $objdir/info/commit-graph && graph_read_expect -C full 11 "generation_data extra_edges"
graph_read_expect "11" "generation_data extra_edges"
' '
graph_git_behavior 'cleared graph, commit 8 vs merge 1' full commits/8 merge/1 graph_git_behavior 'cleared graph, commit 8 vs merge 1' full commits/8 merge/1
graph_git_behavior 'cleared graph, commit 8 vs merge 2' full commits/8 merge/2 graph_git_behavior 'cleared graph, commit 8 vs merge 2' full commits/8 merge/2
test_expect_success 'build graph from latest pack with closure' ' test_expect_success 'build graph from latest pack with closure' '
cd "$TRASH_DIRECTORY/full" && git -C full commit-graph write --stdin-packs <new-idx &&
cat new-idx | git commit-graph write --stdin-packs && test_path_is_file full/$objdir/info/commit-graph &&
test_path_is_file $objdir/info/commit-graph && graph_read_expect -C full 9 "generation_data extra_edges"
graph_read_expect "9" "generation_data extra_edges"
' '
graph_git_behavior 'graph from pack, commit 8 vs merge 1' full commits/8 merge/1 graph_git_behavior 'graph from pack, commit 8 vs merge 1' full commits/8 merge/1
graph_git_behavior 'graph from pack, commit 8 vs merge 2' full commits/8 merge/2 graph_git_behavior 'graph from pack, commit 8 vs merge 2' full commits/8 merge/2
test_expect_success 'build graph from commits with closure' ' test_expect_success 'build graph from commits with closure' '
cd "$TRASH_DIRECTORY/full" && git -C full tag -a -m "merge" tag/merge merge/2 &&
git tag -a -m "merge" tag/merge merge/2 && git -C full rev-parse tag/merge >commits-in &&
git rev-parse tag/merge >commits-in && git -C full rev-parse merge/1 >>commits-in &&
git rev-parse merge/1 >>commits-in && git -C full commit-graph write --stdin-commits <commits-in &&
cat commits-in | git commit-graph write --stdin-commits && test_path_is_file full/$objdir/info/commit-graph &&
test_path_is_file $objdir/info/commit-graph && graph_read_expect -C full 6 "generation_data"
graph_read_expect "6" "generation_data"
' '
graph_git_behavior 'graph from commits, commit 8 vs merge 1' full commits/8 merge/1 graph_git_behavior 'graph from commits, commit 8 vs merge 1' full commits/8 merge/1
graph_git_behavior 'graph from commits, commit 8 vs merge 2' full commits/8 merge/2 graph_git_behavior 'graph from commits, commit 8 vs merge 2' full commits/8 merge/2
test_expect_success 'build graph from commits with append' ' test_expect_success 'build graph from commits with append' '
cd "$TRASH_DIRECTORY/full" && git -C full rev-parse merge/3 >in &&
git rev-parse merge/3 | git commit-graph write --stdin-commits --append && git -C full commit-graph write --stdin-commits --append <in &&
test_path_is_file $objdir/info/commit-graph && test_path_is_file full/$objdir/info/commit-graph &&
graph_read_expect "10" "generation_data extra_edges" graph_read_expect -C full 10 "generation_data extra_edges"
' '
graph_git_behavior 'append graph, commit 8 vs merge 1' full commits/8 merge/1 graph_git_behavior 'append graph, commit 8 vs merge 1' full commits/8 merge/1
graph_git_behavior 'append graph, commit 8 vs merge 2' full commits/8 merge/2 graph_git_behavior 'append graph, commit 8 vs merge 2' full commits/8 merge/2
test_expect_success 'build graph using --reachable' ' test_expect_success 'build graph using --reachable' '
cd "$TRASH_DIRECTORY/full" && git -C full commit-graph write --reachable &&
git commit-graph write --reachable && test_path_is_file full/$objdir/info/commit-graph &&
test_path_is_file $objdir/info/commit-graph && graph_read_expect -C full 11 "generation_data extra_edges"
graph_read_expect "11" "generation_data extra_edges"
' '
graph_git_behavior 'append graph, commit 8 vs merge 1' full commits/8 merge/1 graph_git_behavior 'append graph, commit 8 vs merge 1' full commits/8 merge/1
graph_git_behavior 'append graph, commit 8 vs merge 2' full commits/8 merge/2 graph_git_behavior 'append graph, commit 8 vs merge 2' full commits/8 merge/2
test_expect_success 'setup bare repo' ' test_expect_success 'setup bare repo' '
cd "$TRASH_DIRECTORY" && git clone --bare --no-local full bare
git clone --bare --no-local full bare &&
cd bare &&
git config core.commitGraph true &&
baredir="./objects"
' '
graph_git_behavior 'bare repo, commit 8 vs merge 1' bare commits/8 merge/1 graph_git_behavior 'bare repo, commit 8 vs merge 1' bare commits/8 merge/1
graph_git_behavior 'bare repo, commit 8 vs merge 2' bare commits/8 merge/2 graph_git_behavior 'bare repo, commit 8 vs merge 2' bare commits/8 merge/2
test_expect_success 'write graph in bare repo' ' test_expect_success 'write graph in bare repo' '
cd "$TRASH_DIRECTORY/bare" && git -C bare commit-graph write &&
git commit-graph write && test_path_is_file bare/objects/info/commit-graph &&
test_path_is_file $baredir/info/commit-graph && graph_read_expect -C bare 11 "generation_data extra_edges"
graph_read_expect "11" "generation_data extra_edges"
' '
graph_git_behavior 'bare repo with graph, commit 8 vs merge 1' bare commits/8 merge/1 graph_git_behavior 'bare repo with graph, commit 8 vs merge 1' bare commits/8 merge/1
graph_git_behavior 'bare repo with graph, commit 8 vs merge 2' bare commits/8 merge/2 graph_git_behavior 'bare repo with graph, commit 8 vs merge 2' bare commits/8 merge/2
test_expect_success 'perform fast-forward merge in full repo' ' test_expect_success 'perform fast-forward merge in full repo' '
cd "$TRASH_DIRECTORY/full" && git -C full checkout -b merge-5-to-8 commits/5 &&
git checkout -b merge-5-to-8 commits/5 && git -C full merge commits/8 &&
git merge commits/8 && git -C full show-ref -s merge-5-to-8 >output &&
git show-ref -s merge-5-to-8 >output && git -C full show-ref -s commits/8 >expect &&
git show-ref -s commits/8 >expect &&
test_cmp expect output test_cmp expect output
' '
test_expect_success 'check that gc computes commit-graph' ' test_expect_success 'check that gc computes commit-graph' '
cd "$TRASH_DIRECTORY/full" && test_commit -C full --no-tag blank &&
git commit --allow-empty -m "blank" && git -C full commit-graph write --reachable &&
git commit-graph write --reachable && cp full/$objdir/info/commit-graph commit-graph-before-gc &&
cp $objdir/info/commit-graph commit-graph-before-gc && git -C full reset --hard HEAD~1 &&
git reset --hard HEAD~1 && test_config -C full gc.writeCommitGraph true &&
git config gc.writeCommitGraph true && git -C full gc &&
git gc && cp full/$objdir/info/commit-graph commit-graph-after-gc &&
cp $objdir/info/commit-graph commit-graph-after-gc &&
! test_cmp_bin commit-graph-before-gc commit-graph-after-gc && ! test_cmp_bin commit-graph-before-gc commit-graph-after-gc &&
git commit-graph write --reachable && git -C full commit-graph write --reachable &&
test_cmp_bin commit-graph-after-gc $objdir/info/commit-graph test_cmp_bin commit-graph-after-gc full/$objdir/info/commit-graph
' '
test_expect_success 'replace-objects invalidates commit-graph' ' test_expect_success 'replace-objects invalidates commit-graph' '
cd "$TRASH_DIRECTORY" &&
test_when_finished rm -rf replace && test_when_finished rm -rf replace &&
git clone full replace && git clone full replace &&
( (
@ -359,7 +328,6 @@ test_expect_success 'replace-objects invalidates commit-graph' '
' '
test_expect_success 'commit grafts invalidate commit-graph' ' test_expect_success 'commit grafts invalidate commit-graph' '
cd "$TRASH_DIRECTORY" &&
test_when_finished rm -rf graft && test_when_finished rm -rf graft &&
git clone --template= full graft && git clone --template= full graft &&
( (
@ -384,7 +352,6 @@ test_expect_success 'commit grafts invalidate commit-graph' '
' '
test_expect_success 'replace-objects invalidates commit-graph' ' test_expect_success 'replace-objects invalidates commit-graph' '
cd "$TRASH_DIRECTORY" &&
test_when_finished rm -rf shallow && test_when_finished rm -rf shallow &&
git clone --depth 2 "file://$TRASH_DIRECTORY/full" shallow && git clone --depth 2 "file://$TRASH_DIRECTORY/full" shallow &&
( (
@ -427,24 +394,25 @@ test_expect_success 'warn on improper hash version' '
' '
test_expect_success TIME_IS_64BIT,TIME_T_IS_64BIT 'lower layers have overflow chunk' ' test_expect_success TIME_IS_64BIT,TIME_T_IS_64BIT 'lower layers have overflow chunk' '
cd "$TRASH_DIRECTORY/full" &&
UNIX_EPOCH_ZERO="@0 +0000" && UNIX_EPOCH_ZERO="@0 +0000" &&
FUTURE_DATE="@4147483646 +0000" && FUTURE_DATE="@4147483646 +0000" &&
rm -f .git/objects/info/commit-graph && rm -f full/.git/objects/info/commit-graph &&
test_commit --date "$FUTURE_DATE" future-1 && test_commit -C full --date "$FUTURE_DATE" future-1 &&
test_commit --date "$UNIX_EPOCH_ZERO" old-1 && test_commit -C full --date "$UNIX_EPOCH_ZERO" old-1 &&
git commit-graph write --reachable && git -C full commit-graph write --reachable &&
test_commit --date "$FUTURE_DATE" future-2 && test_commit -C full --date "$FUTURE_DATE" future-2 &&
test_commit --date "$UNIX_EPOCH_ZERO" old-2 && test_commit -C full --date "$UNIX_EPOCH_ZERO" old-2 &&
git commit-graph write --reachable --split=no-merge && git -C full commit-graph write --reachable --split=no-merge &&
test_commit extra && test_commit -C full extra &&
git commit-graph write --reachable --split=no-merge && git -C full commit-graph write --reachable --split=no-merge &&
git commit-graph write --reachable && git -C full commit-graph write --reachable &&
graph_read_expect 16 "generation_data generation_data_overflow extra_edges" && graph_read_expect -C full 16 \
mv .git/objects/info/commit-graph commit-graph-upgraded && "generation_data generation_data_overflow extra_edges" &&
git commit-graph write --reachable && mv full/.git/objects/info/commit-graph commit-graph-upgraded &&
graph_read_expect 16 "generation_data generation_data_overflow extra_edges" && git -C full commit-graph write --reachable &&
test_cmp .git/objects/info/commit-graph commit-graph-upgraded graph_read_expect -C full 16 \
"generation_data generation_data_overflow extra_edges" &&
test_cmp full/.git/objects/info/commit-graph commit-graph-upgraded
' '
# the verify tests below expect the commit-graph to contain # the verify tests below expect the commit-graph to contain
@ -454,10 +422,11 @@ test_expect_success TIME_IS_64BIT,TIME_T_IS_64BIT 'lower layers have overflow ch
# and the tests will likely break. # and the tests will likely break.
test_expect_success 'git commit-graph verify' ' test_expect_success 'git commit-graph verify' '
cd "$TRASH_DIRECTORY/full" && git -C full rev-parse commits/8 >in &&
git rev-parse commits/8 | git -c commitGraph.generationVersion=1 commit-graph write --stdin-commits && git -C full -c commitGraph.generationVersion=1 commit-graph write \
git commit-graph verify >output && --stdin-commits <in &&
graph_read_expect 9 extra_edges 1 git -C full commit-graph verify >output &&
graph_read_expect -C full 9 extra_edges 1
' '
NUM_COMMITS=9 NUM_COMMITS=9
@ -495,25 +464,24 @@ GRAPH_BYTE_OCTOPUS=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4))
GRAPH_BYTE_FOOTER=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4 * $NUM_OCTOPUS_EDGES)) GRAPH_BYTE_FOOTER=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4 * $NUM_OCTOPUS_EDGES))
corrupt_graph_setup() { corrupt_graph_setup() {
cd "$TRASH_DIRECTORY/full" && test_when_finished mv commit-graph-backup full/$objdir/info/commit-graph &&
test_when_finished mv commit-graph-backup $objdir/info/commit-graph && cp full/$objdir/info/commit-graph commit-graph-backup &&
cp $objdir/info/commit-graph commit-graph-backup && chmod u+w full/$objdir/info/commit-graph
chmod u+w $objdir/info/commit-graph
} }
corrupt_graph_verify() { corrupt_graph_verify() {
grepstr=$1 grepstr=$1
test_must_fail git commit-graph verify 2>test_err && test_must_fail git -C full commit-graph verify 2>test_err &&
grep -v "^+" test_err >err && grep -v "^+" test_err >err &&
test_i18ngrep "$grepstr" err && test_i18ngrep "$grepstr" err &&
if test "$2" != "no-copy" if test "$2" != "no-copy"
then then
cp $objdir/info/commit-graph commit-graph-pre-write-test cp full/$objdir/info/commit-graph commit-graph-pre-write-test
fi && fi &&
git status --short && git -C full status --short &&
GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE=true git commit-graph write && GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE=true git -C full commit-graph write &&
chmod u+w $objdir/info/commit-graph && chmod u+w full/$objdir/info/commit-graph &&
git commit-graph verify git -C full commit-graph verify
} }
# usage: corrupt_graph_and_verify <position> <data> <string> [<zero_pos>] # usage: corrupt_graph_and_verify <position> <data> <string> [<zero_pos>]
@ -527,24 +495,24 @@ corrupt_graph_and_verify() {
data="${2:-\0}" data="${2:-\0}"
grepstr=$3 grepstr=$3
corrupt_graph_setup && corrupt_graph_setup &&
orig_size=$(wc -c < $objdir/info/commit-graph) && orig_size=$(wc -c <full/$objdir/info/commit-graph) &&
zero_pos=${4:-${orig_size}} && zero_pos=${4:-${orig_size}} &&
printf "$data" | dd of="$objdir/info/commit-graph" bs=1 seek="$pos" conv=notrunc && printf "$data" | dd of="full/$objdir/info/commit-graph" bs=1 seek="$pos" conv=notrunc &&
dd of="$objdir/info/commit-graph" bs=1 seek="$zero_pos" if=/dev/null && dd of="full/$objdir/info/commit-graph" bs=1 seek="$zero_pos" if=/dev/null &&
test-tool genzeros $(($orig_size - $zero_pos)) >>"$objdir/info/commit-graph" && test-tool genzeros $(($orig_size - $zero_pos)) >>"full/$objdir/info/commit-graph" &&
corrupt_graph_verify "$grepstr" corrupt_graph_verify "$grepstr"
} }
test_expect_success POSIXPERM,SANITY 'detect permission problem' ' test_expect_success POSIXPERM,SANITY 'detect permission problem' '
corrupt_graph_setup && corrupt_graph_setup &&
chmod 000 $objdir/info/commit-graph && chmod 000 full/$objdir/info/commit-graph &&
corrupt_graph_verify "Could not open" "no-copy" corrupt_graph_verify "Could not open" "no-copy"
' '
test_expect_success 'detect too small' ' test_expect_success 'detect too small' '
corrupt_graph_setup && corrupt_graph_setup &&
echo "a small graph" >$objdir/info/commit-graph && echo "a small graph" >full/$objdir/info/commit-graph &&
corrupt_graph_verify "too small" corrupt_graph_verify "too small"
' '
@ -655,33 +623,30 @@ test_expect_success 'detect incorrect chunk count' '
' '
test_expect_success 'git fsck (checks commit-graph when config set to true)' ' test_expect_success 'git fsck (checks commit-graph when config set to true)' '
cd "$TRASH_DIRECTORY/full" && git -C full fsck &&
git fsck &&
corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \ corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \
"incorrect checksum" && "incorrect checksum" &&
cp commit-graph-pre-write-test $objdir/info/commit-graph && cp commit-graph-pre-write-test full/$objdir/info/commit-graph &&
test_must_fail git -c core.commitGraph=true fsck test_must_fail git -C full -c core.commitGraph=true fsck
' '
test_expect_success 'git fsck (ignores commit-graph when config set to false)' ' test_expect_success 'git fsck (ignores commit-graph when config set to false)' '
cd "$TRASH_DIRECTORY/full" && git -C full fsck &&
git fsck &&
corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \ corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \
"incorrect checksum" && "incorrect checksum" &&
cp commit-graph-pre-write-test $objdir/info/commit-graph && cp commit-graph-pre-write-test full/$objdir/info/commit-graph &&
git -c core.commitGraph=false fsck git -C full -c core.commitGraph=false fsck
' '
test_expect_success 'git fsck (checks commit-graph when config unset)' ' test_expect_success 'git fsck (checks commit-graph when config unset)' '
cd "$TRASH_DIRECTORY/full" && test_when_finished "git -C full config core.commitGraph true" &&
test_when_finished "git config core.commitGraph true" &&
git fsck && git -C full fsck &&
corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \ corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \
"incorrect checksum" && "incorrect checksum" &&
test_unconfig core.commitGraph && test_unconfig -C full core.commitGraph &&
cp commit-graph-pre-write-test $objdir/info/commit-graph && cp commit-graph-pre-write-test full/$objdir/info/commit-graph &&
test_must_fail git fsck test_must_fail git -C full fsck
' '
test_expect_success 'git fsck shows commit-graph output with --progress' ' test_expect_success 'git fsck shows commit-graph output with --progress' '
@ -792,32 +757,33 @@ test_expect_success 'corrupt commit-graph write (missing tree)' '
# #
test_expect_success 'set up and verify repo with generation data overflow chunk' ' test_expect_success 'set up and verify repo with generation data overflow chunk' '
objdir=".git/objects" &&
UNIX_EPOCH_ZERO="@0 +0000" && UNIX_EPOCH_ZERO="@0 +0000" &&
FUTURE_DATE="@2147483646 +0000" && FUTURE_DATE="@2147483646 +0000" &&
cd "$TRASH_DIRECTORY" &&
mkdir repo && git init repo &&
cd repo && (
git init && cd repo &&
test_commit --date "$UNIX_EPOCH_ZERO" 1 &&
test_commit 2 && test_commit --date "$UNIX_EPOCH_ZERO" 1 &&
test_commit --date "$UNIX_EPOCH_ZERO" 3 && test_commit 2 &&
git commit-graph write --reachable && test_commit --date "$UNIX_EPOCH_ZERO" 3 &&
graph_read_expect 3 generation_data && git commit-graph write --reachable &&
test_commit --date "$FUTURE_DATE" 4 && graph_read_expect 3 generation_data &&
test_commit 5 && test_commit --date "$FUTURE_DATE" 4 &&
test_commit --date "$UNIX_EPOCH_ZERO" 6 && test_commit 5 &&
git branch left && test_commit --date "$UNIX_EPOCH_ZERO" 6 &&
git reset --hard 3 && git branch left &&
test_commit 7 && git reset --hard 3 &&
test_commit --date "$FUTURE_DATE" 8 && test_commit 7 &&
test_commit 9 && test_commit --date "$FUTURE_DATE" 8 &&
git branch right && test_commit 9 &&
git reset --hard 3 && git branch right &&
test_merge M left right && git reset --hard 3 &&
git commit-graph write --reachable && test_merge M left right &&
graph_read_expect 10 "generation_data generation_data_overflow" && git commit-graph write --reachable &&
git commit-graph verify graph_read_expect 10 "generation_data generation_data_overflow" &&
git commit-graph verify
)
' '
graph_git_behavior 'generation data overflow chunk repo' repo left right graph_git_behavior 'generation data overflow chunk repo' repo left right

View File

@ -37,39 +37,39 @@ test_expect_success 'lower layers have overflow chunk' '
graph_git_behavior 'overflow' '' HEAD~2 HEAD graph_git_behavior 'overflow' '' HEAD~2 HEAD
test_expect_success 'set up and verify repo with generation data overflow chunk' ' test_expect_success 'set up and verify repo with generation data overflow chunk' '
mkdir repo && git init repo &&
cd repo && (
git init && cd repo &&
test_commit --date "$UNIX_EPOCH_ZERO" 1 && test_commit --date "$UNIX_EPOCH_ZERO" 1 &&
test_commit 2 && test_commit 2 &&
test_commit --date "$UNIX_EPOCH_ZERO" 3 && test_commit --date "$UNIX_EPOCH_ZERO" 3 &&
git commit-graph write --reachable && git commit-graph write --reachable &&
graph_read_expect 3 generation_data && graph_read_expect 3 generation_data &&
test_commit --date "$FUTURE_DATE" 4 && test_commit --date "$FUTURE_DATE" 4 &&
test_commit 5 && test_commit 5 &&
test_commit --date "$UNIX_EPOCH_ZERO" 6 && test_commit --date "$UNIX_EPOCH_ZERO" 6 &&
git branch left && git branch left &&
git reset --hard 3 && git reset --hard 3 &&
test_commit 7 && test_commit 7 &&
test_commit --date "$FUTURE_DATE" 8 && test_commit --date "$FUTURE_DATE" 8 &&
test_commit 9 && test_commit 9 &&
git branch right && git branch right &&
git reset --hard 3 && git reset --hard 3 &&
test_merge M left right && test_merge M left right &&
git commit-graph write --reachable && git commit-graph write --reachable &&
graph_read_expect 10 "generation_data generation_data_overflow" && graph_read_expect 10 "generation_data generation_data_overflow" &&
git commit-graph verify git commit-graph verify
)
' '
graph_git_behavior 'overflow 2' repo left right graph_git_behavior 'overflow 2' repo left right
test_expect_success 'single commit with generation data exceeding UINT32_MAX' ' test_expect_success 'single commit with generation data exceeding UINT32_MAX' '
git init repo-uint32-max && git init repo-uint32-max &&
cd repo-uint32-max && test_commit -C repo-uint32-max --date "@4294967297 +0000" 1 &&
test_commit --date "@4294967297 +0000" 1 && git -C repo-uint32-max commit-graph write --reachable &&
git commit-graph write --reachable && graph_read_expect -C repo-uint32-max 1 "generation_data" &&
graph_read_expect 1 "generation_data" && git -C repo-uint32-max commit-graph verify
git commit-graph verify
' '
test_done test_done

View File

@ -619,6 +619,12 @@ test_expect_success TTY 'create --quiet disables all bundle progress' '
test_must_be_empty err test_must_be_empty err
' '
test_expect_success 'bundle progress with --no-quiet' '
GIT_PROGRESS_DELAY=0 \
git bundle create --no-quiet out.bundle --all 2>err &&
grep "%" err
'
test_expect_success 'read bundle over stdin' ' test_expect_success 'read bundle over stdin' '
git bundle create some.bundle HEAD && git bundle create some.bundle HEAD &&

View File

@ -174,6 +174,13 @@ test_expect_success 'do not move directory over existing directory' '
test_must_fail git mv path2 path0 test_must_fail git mv path2 path0
' '
test_expect_success 'rename directory to non-existing directory' '
mkdir dir-a &&
>dir-a/f &&
git add dir-a &&
git mv dir-a non-existing-dir
'
test_expect_success 'move into "."' ' test_expect_success 'move into "."' '
git mv path1/path2/ . git mv path1/path2/ .
' '

View File

@ -20,10 +20,19 @@ test_expect_success 'empty name and missing email' '
' '
test_expect_success 'commit rejects all-crud name' ' test_expect_success 'commit rejects all-crud name' '
test_must_fail env GIT_AUTHOR_NAME=" .;<>" \ test_must_fail env GIT_AUTHOR_NAME=" ,;<>" \
git commit --allow-empty -m foo git commit --allow-empty -m foo
' '
test_expect_success 'commit does not strip trailing dot' '
author_name="Pat Doe Jr." &&
env GIT_AUTHOR_NAME="$author_name" \
git commit --allow-empty -m foo &&
git log -1 --format=%an >actual &&
echo "$author_name" >expected &&
test_cmp actual expected
'
# We must test the actual error message here, as an unwanted # We must test the actual error message here, as an unwanted
# auto-detection could fail for other reasons. # auto-detection could fail for other reasons.
test_expect_success 'empty configured name does not auto-detect' ' test_expect_success 'empty configured name does not auto-detect' '

View File

@ -337,13 +337,14 @@ test_expect_success $PREREQ 'Show all headers' '
test_expect_success $PREREQ 'Prompting works' ' test_expect_success $PREREQ 'Prompting works' '
clean_fake_sendmail && clean_fake_sendmail &&
(echo "to@example.com" && (echo "to@example.com" &&
echo "" echo "my-message-id@example.com"
) | GIT_SEND_EMAIL_NOTTY=1 git send-email \ ) | GIT_SEND_EMAIL_NOTTY=1 git send-email \
--smtp-server="$(pwd)/fake.sendmail" \ --smtp-server="$(pwd)/fake.sendmail" \
$patches \ $patches \
2>errors && 2>errors &&
grep "^From: A U Thor <author@example.com>\$" msgtxt1 && grep "^From: A U Thor <author@example.com>\$" msgtxt1 &&
grep "^To: to@example.com\$" msgtxt1 grep "^To: to@example.com\$" msgtxt1 &&
grep "^In-Reply-To: <my-message-id@example.com>" msgtxt1
' '
test_expect_success $PREREQ,AUTOIDENT 'implicit ident is allowed' ' test_expect_success $PREREQ,AUTOIDENT 'implicit ident is allowed' '
@ -659,7 +660,6 @@ test_expect_success $PREREQ 'clear message-id before parsing a new message' '
clean_fake_sendmail && clean_fake_sendmail &&
echo true | write_script my-hooks/sendemail-validate && echo true | write_script my-hooks/sendemail-validate &&
test_config core.hooksPath my-hooks && test_config core.hooksPath my-hooks &&
GIT_SEND_EMAIL_NOTTY=1 \
git send-email --validate --to=recipient@example.com \ git send-email --validate --to=recipient@example.com \
--smtp-server="$(pwd)/fake.sendmail" \ --smtp-server="$(pwd)/fake.sendmail" \
$patches $threaded_patches && $patches $threaded_patches &&

View File

@ -1291,6 +1291,39 @@ test_cmp_rev () {
fi fi
} }
# Tests that a commit message matches the expected text
#
# Usage: test_commit_message <rev> [-m <msg> | <file>]
#
# When using "-m" <msg> will have a line feed appended. If the second
# argument is omitted then the expected message is read from stdin.
test_commit_message () {
local msg_file=expect.msg
case $# in
3)
if test "$2" = "-m"
then
printf "%s\n" "$3" >"$msg_file"
else
BUG "Usage: test_commit_message <rev> [-m <message> | <file>]"
fi
;;
2)
msg_file="$2"
;;
1)
cat >"$msg_file"
;;
*)
BUG "Usage: test_commit_message <rev> [-m <message> | <file>]"
;;
esac
git show --no-patch --pretty=format:%B "$1" -- >actual.msg &&
test_cmp "$msg_file" actual.msg
}
# Compare paths respecting core.ignoreCase # Compare paths respecting core.ignoreCase
test_cmp_fspath () { test_cmp_fspath () {
if test "x$1" = "x$2" if test "x$1" = "x$2"