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
/cscope*
/compile_commands.json
/.cache/
*.hcc
*.obj
*.lib

View File

@ -80,6 +80,7 @@ Frank Lichtenheld <frank@lichtenheld.de> <flichtenheld@astaro.com>
Fredrik Kuivinen <frekui@gmail.com> <freku045@student.liu.se>
Frédéric Heitzmann <frederic.heitzmann@gmail.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@ksplice.com>
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
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.
@ -252,6 +258,36 @@ Fixes since v2.41
submodule.<name>.update configuration variable.
(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.
(merge 51f9d2e563 sa/doc-ls-remote 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 36f76d2a25 rs/pack-objects-parseopt-fix 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
------------
If the `DISPLAY` environment variable is not set, 'git log' is used
instead. You can also give command-line options such as `-p` and
`--stat`.
Git detects a graphical environment through various environment variables:
`DISPLAY`, which is set in X Window System environments on Unix systems.
`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

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
repositories will be set to this value. This value is
ignored when cloning and the setting of the remote repository
is always used. The default is "sha1". THIS VARIABLE IS
EXPERIMENTAL! See `--object-format` in linkgit:git-init[1].
is always used. The default is "sha1".
See `--object-format` in linkgit:git-init[1].
Git Commits
~~~~~~~~~~~

View File

@ -1,6 +1,9 @@
THIS OPTION IS EXPERIMENTAL! SHA-256 support is experimental and still
in an early stage. A SHA-256 repository will in general not be able to
share work with "regular" SHA-1 repositories. It should be assumed
that, e.g., Git internal file formats in relation to SHA-256
repositories may change in backwards-incompatible ways. Only use
`--object-format=sha256` for testing purposes.
Note: At present, there is no interoperability between SHA-256
repositories and SHA-1 repositories.
Historically, we warned that SHA-256 repositories may later need
backward incompatible changes when we introduce such interoperability
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
GVF=GIT-VERSION-FILE
DEF_VER=v2.42.0-rc0
DEF_VER=v2.42.0-rc2
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
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)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
@ -3216,6 +3223,12 @@ $(SP_OBJ): %.sp: %.c %.o
sparse: $(SP_OBJ)
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
EXCEPT_HDRS += sha256/nettle.h
endif
@ -3652,6 +3665,7 @@ clean: profile-clean coverage-clean cocciclean
$(RM) po/git.pot po/git-core.pot
$(RM) git.res
$(RM) $(OBJECTS)
$(RM) headless-git.o
$(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(REFTABLE_TEST_LIB)
$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS)
$(RM) $(TEST_PROGRAMS)
@ -3680,6 +3694,7 @@ endif
$(RM) GIT-SCRIPT-DEFINES GIT-PERL-DEFINES GIT-PERL-HEADER GIT-PYTHON-VARS
ifdef MSVC
$(RM) $(patsubst %.o,%.o.pdb,$(OBJECTS))
$(RM) headless-git.o.pdb
$(RM) $(patsubst %.exe,%.pdb,$(OTHER_PROGRAMS))
$(RM) $(patsubst %.exe,%.iobj,$(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."));
else if (!strcmp(me, "revert"))
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
error(_("It is not possible to %s because you have unmerged files."),
me);
BUG("Unhandled conflict reason '%s'", me);
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) {
int all_progress_implied = 1;
int progress = isatty(STDERR_FILENO);
struct strvec pack_opts;
struct strvec pack_opts = STRVEC_INIT;
int version = -1;
int ret;
struct option options[] = {
OPT_SET_INT('q', "quiet", &progress,
N_("do not show progress meter"), 0),
OPT_SET_INT(0, "progress", &progress,
N_("show progress meter"), 1),
OPT_SET_INT_F(0, "all-progress", &progress,
N_("historical; same as --progress"), 2,
PARSE_OPT_HIDDEN),
OPT_HIDDEN_BOOL(0, "all-progress-implied",
&all_progress_implied,
N_("historical; does nothing")),
OPT_PASSTHRU_ARGV('q', "quiet", &pack_opts, NULL,
N_("do not show progress meter"),
PARSE_OPT_NOARG),
OPT_PASSTHRU_ARGV(0, "progress", &pack_opts, NULL,
N_("show progress meter"),
PARSE_OPT_NOARG),
OPT_PASSTHRU_ARGV(0, "all-progress", &pack_opts, NULL,
N_("historical; same as --progress"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN),
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,
N_("specify bundle format version")),
OPT_END()
};
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,
builtin_bundle_create_usage, options, &bundle_file);
/* 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)
die(_("Need a repository to create a bundle."));
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"
"<Actions Context=\"Author\">\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"
"</Exec>\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;
struct strbuf a_src_dir = STRBUF_INIT;
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 lock_file lock_file = LOCK_INIT;
struct cache_entry *ce;
@ -304,7 +304,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
goto act_on_entry;
}
if (S_ISDIR(st.st_mode)
&& lstat(dst, &st) == 0) {
&& lstat(dst, &dest_st) == 0) {
bad = _("cannot move directory over file");
goto act_on_entry;
}

View File

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

View File

@ -1347,6 +1347,11 @@ static char *path_lookup(const char *cmd, int exe_only)
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)
{
while (*s && *s != c)

View File

@ -177,6 +177,9 @@ pid_t waitpid(pid_t pid, int *status, int options);
#define kill mingw_kill
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
#include <openssl/ssl.h>
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
X = .exe
EXTRA_PROGRAMS += headless-git$X
compat/msvc.o: compat/msvc.c compat/mingw.c GIT-CFLAGS
endif
ifeq ($(uname_S),Interix)
@ -705,6 +707,7 @@ ifeq ($(uname_S),MINGW)
COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \
-fstack-protector-strong
EXTLIBS += -lntdll
EXTRA_PROGRAMS += headless-git$X
INSTALL = /bin/install
INTERNAL_QSORT = YesPlease
HAVE_LIBCHARSET_H = YesPlease

View File

@ -738,6 +738,15 @@ if(WIN32)
else()
message(FATAL_ERROR "Unhandled compiler: ${CMAKE_C_COMPILER_ID}")
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)
target_link_libraries(common-main pthread rt)
endif()

View File

@ -76,7 +76,7 @@ sub createProject {
my $libs_release = "\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_debug = $libs_release;
$libs_debug =~ s/zlib\.lib/zlibd\.lib/g;
@ -230,7 +230,7 @@ EOM
print F << "EOM";
</ItemGroup>
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_libreftable = $$build_structure{"LIBS_reftable/libreftable_GUID"};
my $uuid_xdiff_lib = $$build_structure{"LIBS_xdiff/lib_GUID"};

View File

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

View File

@ -26,18 +26,6 @@ use Git::I18N;
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 {
print <<EOT;
git send-email' [<options>] <file|directory>
@ -971,17 +959,19 @@ EOT3
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;
$ENV{"GIT_SEND_EMAIL_NOTTY"}
? Term::ReadLine->new('git-send-email', \*STDIN, \*STDOUT)
: Term::ReadLine->new('git-send-email');
};
if ($@) {
$term = FakeTerm->new("$@: going non-interactive");
if (!defined $term) {
$term = $ENV{"GIT_SEND_EMAIL_NOTTY"}
? Term::ReadLine->new('git-send-email', \*STDIN, \*STDOUT)
: Term::ReadLine->new('git-send-email');
}
return $term;
}
return $term;
}
sub ask {

View File

@ -4,7 +4,11 @@
#if defined(SHA1_APPLE)
#include <CommonCrypto/CommonDigest.h>
#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)
#include "sha1dc_git.h"
#else /* SHA1_BLK */
@ -17,7 +21,11 @@
#define SHA256_NEEDS_CLONE_HELPER
#include "sha256/gcrypt.h"
#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
#include "sha256/block/sha256.h"
#endif
@ -41,6 +49,10 @@
#define git_SHA1_Update platform_SHA1_Update
#define git_SHA1_Final platform_SHA1_Final
#ifdef platform_SHA1_Clone
#define git_SHA1_Clone platform_SHA1_Clone
#endif
#ifndef platform_SHA256_CTX
#define platform_SHA256_CTX SHA256_CTX
#define platform_SHA256_Init SHA256_Init
@ -63,10 +75,12 @@
#define git_SHA1_Update git_SHA1_Update_Chunked
#endif
#ifndef SHA1_NEEDS_CLONE_HELPER
static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src)
{
memcpy(dst, src, sizeof(*dst));
}
#endif
#ifndef SHA256_NEEDS_CLONE_HELPER
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)
{
return c <= 32 ||
c == '.' ||
c == ',' ||
c == ':' ||
c == ';' ||

View File

@ -480,6 +480,9 @@ static void parse_options_check(const struct option *opts)
opts->long_name))
optbug(opts, "uses feature "
"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) {
case OPTION_COUNTUP:
case OPTION_BIT:

View File

@ -170,6 +170,7 @@ int is_executable(const char *name)
return st.st_mode & S_IXUSR;
}
#ifndef locate_in_PATH
/*
* Search $PATH for a command. This emulates the path search that
* 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);
return NULL;
}
#endif
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
* the latest commit message.
*/
int res = 0;
struct commit *commit;
const char *msg;
const char *path = rebase_path_squash_msg();
const char *encoding = get_commit_output_encoding();
if (parse_head(r, &commit) ||
!(p = repo_logmsg_reencode(r, commit, NULL, encoding)) ||
write_message(p, strlen(p), path, 0)) {
repo_unuse_commit_buffer(r, commit, p);
return error(_("could not write file: "
"'%s'"), path);
if (parse_head(r, &commit))
return error(_("could not parse HEAD"));
p = repo_logmsg_reencode(r, commit, NULL, encoding);
if (!p) {
res = error(_("could not parse commit %s"),
oid_to_hex(&commit->object.oid));
goto unuse_commit_buffer;
}
repo_unuse_commit_buffer(r,
commit, p);
find_commit_subject(p, &msg);
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;
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);
}
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);
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);
}

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
/t8005/*.txt 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
}
# 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() {
MSG=$1
DIR=$2
BRANCH=$3
COMPARE=$4
test_expect_success "check normal git operations: $MSG" '
cd "$TRASH_DIRECTORY/$DIR" &&
graph_git_two_modes "log --oneline $BRANCH" &&
graph_git_two_modes "log --topo-order $BRANCH" &&
graph_git_two_modes "log --graph $COMPARE..$BRANCH" &&
graph_git_two_modes "branch -vv" &&
graph_git_two_modes "merge-base -a $BRANCH $COMPARE"
graph_git_two_modes "${DIR:+-C $DIR} log --oneline $BRANCH" &&
graph_git_two_modes "${DIR:+-C $DIR} log --topo-order $BRANCH" &&
graph_git_two_modes "${DIR:+-C $DIR} log --graph $COMPARE..$BRANCH" &&
graph_git_two_modes "${DIR:+-C $DIR} branch -vv" &&
graph_git_two_modes "${DIR:+-C $DIR} merge-base -a $BRANCH $COMPARE"
'
}
graph_read_expect() {
OPTIONAL=""
NUM_CHUNKS=3
DIR="."
if test "$1" = -C
then
shift
DIR="$1"
shift
fi
if test -n "$2"
then
OPTIONAL=" $2"
@ -47,12 +60,15 @@ graph_read_expect() {
then
OPTIONS=" read_generation_data"
fi
cat >expect <<- EOF
cat >"$DIR/expect" <<-EOF
header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
num_commits: $1
chunks: oid_fanout oid_lookup commit_metadata$OPTIONAL
options:$OPTIONS
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" &&
git checkout -b with-conflicting-fixup &&
test_commit wants-fixup &&
test_commit "fixup! wants-fixup" wants-fixup.t 1 wants-fixup-1 &&
test_commit "fixup! wants-fixup" wants-fixup.t 2 wants-fixup-2 &&
test_commit "fixup! wants-fixup" wants-fixup.t 3 wants-fixup-3 &&
test_commit "fixup 1" wants-fixup.t 1 wants-fixup-1 &&
test_commit "fixup 2" wants-fixup.t 2 wants-fixup-2 &&
test_commit "fixup 3" wants-fixup.t 3 wants-fixup-3 &&
test_must_fail env FAKE_LINES="1 fixup 2 squash 4" \
git rebase -i HEAD~4 &&
: now there is a conflict, and comments in the commit message &&
git show HEAD >out &&
grep "fixup! wants-fixup" out &&
test_commit_message HEAD <<-\EOF &&
# 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 &&
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 &&
: now the comments in the commit message should have been cleaned up &&
git show HEAD >out &&
! grep "fixup! wants-fixup" out &&
test_commit_message HEAD -m wants-fixup &&
: now, let us ensure that "squash" is handled correctly &&
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 &&
: 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_must_fail git rebase --skip) &&
: not the final squash, no need to edit the commit message &&
test_path_is_missing .git/copy.txt &&
: The first squash was skipped, therefore: &&
git show HEAD >out &&
test_i18ngrep "# This is a combination of 2 commits" out &&
test_i18ngrep "# This is the commit message #2:" out &&
: The first and third squashes succeeded, therefore: &&
test_commit_message HEAD <<-\EOF &&
# This is a combination of 3 commits.
# 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) &&
git show HEAD >out &&
test_i18ngrep ! "# This is a combination" out &&
test_commit_message HEAD <<-\EOF &&
wants-fixup
fixup 1
fixup 2
EOF
: Final squash failed, but there was still a squash &&
test_i18ngrep "# This is a combination of 2 commits" .git/copy.txt &&
test_i18ngrep "# This is the commit message #2:" .git/copy.txt
head -n1 .git/copy.txt >first-line &&
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' '

View File

@ -21,21 +21,6 @@ TEST_PASSES_SANITIZE_LEAK=true
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 () {
rev="$1" &&
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_when_finished "rm -f pipe" &&
mkfifo pipe &&
{
(>pipe) &
} &&
test_when_finished "kill $!" &&
test_must_fail git diff --no-index -- pipe a 2>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_when_finished "! kill $!" &&
test_when_finished "kill $! || :" &&
{
(test_write_lines a x c >new) &
} &&
test_when_finished "! kill $!" &&
test_when_finished "kill $! || :" &&
cat >expect <<-EOF &&
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)>
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>
EOF
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>
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>
EOF
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
'
objdir=".git/objects"
test_expect_success 'setup full repo' '
mkdir full &&
cd "$TRASH_DIRECTORY/full" &&
git init &&
git config core.commitGraph true &&
objdir=".git/objects"
git init full
'
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' '
cd "$TRASH_DIRECTORY/full" &&
git commit-graph verify
git -C full commit-graph verify
'
test_expect_success 'write graph with no packs' '
cd "$TRASH_DIRECTORY/full" &&
git commit-graph write --object-dir $objdir &&
test_path_is_missing $objdir/info/commit-graph
git -C full commit-graph write --object-dir $objdir &&
test_path_is_missing full/$objdir/info/commit-graph
'
test_expect_success 'exit with correct error on bad input to --stdin-packs' '
cd "$TRASH_DIRECTORY/full" &&
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_expect_success 'create commits and repack' '
cd "$TRASH_DIRECTORY/full" &&
for i in $(test_seq 3)
do
test_commit $i &&
git branch commits/$i || return 1
test_commit -C full $i &&
git -C full branch commits/$i || return 1
done &&
git repack
git -C full repack
'
. "$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
test_expect_success 'exit with correct error on bad input to --stdin-commits' '
cd "$TRASH_DIRECTORY/full" &&
# invalid, non-hex OID
echo HEAD >in &&
test_expect_code 1 git commit-graph write --stdin-commits <in 2>stderr &&
echo HEAD | test_expect_code 1 git -C full commit-graph write \
--stdin-commits 2>stderr &&
test_i18ngrep "unexpected non-hex object ID: HEAD" stderr &&
# non-existent OID
echo $ZERO_OID >in &&
test_expect_code 1 git commit-graph write --stdin-commits <in 2>stderr &&
echo $ZERO_OID | test_expect_code 1 git -C full commit-graph write \
--stdin-commits 2>stderr &&
test_i18ngrep "invalid object" stderr &&
# valid commit and tree OID
git rev-parse HEAD HEAD^{tree} >in &&
git commit-graph write --stdin-commits <in &&
graph_read_expect 3 generation_data
git -C full rev-parse HEAD HEAD^{tree} >in &&
git -C full commit-graph write --stdin-commits <in &&
graph_read_expect -C full 3 generation_data
'
test_expect_success 'write graph' '
cd "$TRASH_DIRECTORY/full" &&
git commit-graph write &&
test_path_is_file $objdir/info/commit-graph &&
graph_read_expect "3" generation_data
git -C full commit-graph write &&
test_path_is_file full/$objdir/info/commit-graph &&
graph_read_expect -C full 3 generation_data
'
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 &&
test_modebits $objdir/info/commit-graph >actual &&
test_modebits full/$objdir/info/commit-graph >actual &&
test_cmp expect actual
'
graph_git_behavior 'graph exists' full commits/3 commits/1
test_expect_success 'Add more commits' '
cd "$TRASH_DIRECTORY/full" &&
git reset --hard commits/1 &&
git -C full reset --hard commits/1 &&
for i in $(test_seq 4 5)
do
test_commit $i &&
git branch commits/$i || return 1
test_commit -C full $i &&
git -C full branch commits/$i || return 1
done &&
git reset --hard commits/2 &&
git -C full reset --hard commits/2 &&
for i in $(test_seq 6 7)
do
test_commit $i &&
git branch commits/$i || return 1
test_commit -C full $i &&
git -C full branch commits/$i || return 1
done &&
git reset --hard commits/2 &&
git merge commits/4 &&
git branch merge/1 &&
git reset --hard commits/4 &&
git merge commits/6 &&
git branch merge/2 &&
git reset --hard commits/3 &&
git merge commits/5 commits/7 &&
git branch merge/3 &&
git repack
git -C full reset --hard commits/2 &&
git -C full merge commits/4 &&
git -C full branch merge/1 &&
git -C full reset --hard commits/4 &&
git -C full merge commits/6 &&
git -C full branch merge/2 &&
git -C full reset --hard commits/3 &&
git -C full merge commits/5 commits/7 &&
git -C full branch merge/3 &&
git -C full repack
'
test_expect_success 'commit-graph write progress off for redirected stderr' '
cd "$TRASH_DIRECTORY/full" &&
git commit-graph write 2>err &&
git -C full commit-graph write 2>err &&
test_must_be_empty err
'
test_expect_success 'commit-graph write force progress on for stderr' '
cd "$TRASH_DIRECTORY/full" &&
GIT_PROGRESS_DELAY=0 git commit-graph write --progress 2>err &&
GIT_PROGRESS_DELAY=0 git -C full commit-graph write --progress 2>err &&
test_file_not_empty err
'
test_expect_success 'commit-graph write with the --no-progress option' '
cd "$TRASH_DIRECTORY/full" &&
git commit-graph write --no-progress 2>err &&
git -C full commit-graph write --no-progress 2>err &&
test_must_be_empty err
'
test_expect_success 'commit-graph write --stdin-commits progress off for redirected stderr' '
cd "$TRASH_DIRECTORY/full" &&
git rev-parse commits/5 >in &&
git commit-graph write --stdin-commits <in 2>err &&
git -C full rev-parse commits/5 >in &&
git -C full commit-graph write --stdin-commits <in 2>err &&
test_must_be_empty err
'
test_expect_success 'commit-graph write --stdin-commits force progress on for stderr' '
cd "$TRASH_DIRECTORY/full" &&
git rev-parse commits/5 >in &&
GIT_PROGRESS_DELAY=0 git commit-graph write --stdin-commits --progress <in 2>err &&
git -C full rev-parse commits/5 >in &&
GIT_PROGRESS_DELAY=0 git -C full commit-graph write --stdin-commits \
--progress <in 2>err &&
test_i18ngrep "Collecting commits from input" err
'
test_expect_success 'commit-graph write --stdin-commits with the --no-progress option' '
cd "$TRASH_DIRECTORY/full" &&
git rev-parse commits/5 >in &&
git commit-graph write --stdin-commits --no-progress <in 2>err &&
git -C full rev-parse commits/5 >in &&
git -C full commit-graph write --stdin-commits --no-progress <in 2>err &&
test_must_be_empty err
'
test_expect_success 'commit-graph verify progress off for redirected stderr' '
cd "$TRASH_DIRECTORY/full" &&
git commit-graph verify 2>err &&
git -C full commit-graph verify 2>err &&
test_must_be_empty err
'
test_expect_success 'commit-graph verify force progress on for stderr' '
cd "$TRASH_DIRECTORY/full" &&
GIT_PROGRESS_DELAY=0 git commit-graph verify --progress 2>err &&
GIT_PROGRESS_DELAY=0 git -C full commit-graph verify --progress 2>err &&
test_file_not_empty err
'
test_expect_success 'commit-graph verify with the --no-progress option' '
cd "$TRASH_DIRECTORY/full" &&
git commit-graph verify --no-progress 2>err &&
git -C full commit-graph verify --no-progress 2>err &&
test_must_be_empty err
'
@ -194,10 +178,9 @@ test_expect_success 'commit-graph verify with the --no-progress option' '
# 1
test_expect_success 'write graph with merges' '
cd "$TRASH_DIRECTORY/full" &&
git commit-graph write &&
test_path_is_file $objdir/info/commit-graph &&
graph_read_expect "10" "generation_data extra_edges"
git -C full commit-graph write &&
test_path_is_file full/$objdir/info/commit-graph &&
graph_read_expect -C full 10 "generation_data extra_edges"
'
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
test_expect_success 'Add one more commit' '
cd "$TRASH_DIRECTORY/full" &&
test_commit 8 &&
git branch commits/8 &&
ls $objdir/pack | grep idx >existing-idx &&
git repack &&
ls $objdir/pack| grep idx | grep -v -f existing-idx >new-idx
test_commit -C full 8 &&
git -C full branch commits/8 &&
ls full/$objdir/pack | grep idx >existing-idx &&
git -C full repack &&
ls full/$objdir/pack| grep idx | grep -v -f existing-idx >new-idx
'
# 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
test_expect_success 'write graph with new commit' '
cd "$TRASH_DIRECTORY/full" &&
git commit-graph write &&
test_path_is_file $objdir/info/commit-graph &&
graph_read_expect "11" "generation_data extra_edges"
git -C full commit-graph write &&
test_path_is_file full/$objdir/info/commit-graph &&
graph_read_expect -C full 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 2' full commits/8 merge/2
test_expect_success 'write graph with nothing new' '
cd "$TRASH_DIRECTORY/full" &&
git commit-graph write &&
test_path_is_file $objdir/info/commit-graph &&
graph_read_expect "11" "generation_data extra_edges"
git -C full commit-graph write &&
test_path_is_file full/$objdir/info/commit-graph &&
graph_read_expect -C full 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 2' full commits/8 merge/2
test_expect_success 'build graph from latest pack with closure' '
cd "$TRASH_DIRECTORY/full" &&
cat new-idx | git commit-graph write --stdin-packs &&
test_path_is_file $objdir/info/commit-graph &&
graph_read_expect "9" "generation_data extra_edges"
git -C full commit-graph write --stdin-packs <new-idx &&
test_path_is_file full/$objdir/info/commit-graph &&
graph_read_expect -C full 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 2' full commits/8 merge/2
test_expect_success 'build graph from commits with closure' '
cd "$TRASH_DIRECTORY/full" &&
git tag -a -m "merge" tag/merge merge/2 &&
git rev-parse tag/merge >commits-in &&
git rev-parse merge/1 >>commits-in &&
cat commits-in | git commit-graph write --stdin-commits &&
test_path_is_file $objdir/info/commit-graph &&
graph_read_expect "6" "generation_data"
git -C full tag -a -m "merge" tag/merge merge/2 &&
git -C full rev-parse tag/merge >commits-in &&
git -C full rev-parse merge/1 >>commits-in &&
git -C full commit-graph write --stdin-commits <commits-in &&
test_path_is_file full/$objdir/info/commit-graph &&
graph_read_expect -C full 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 2' full commits/8 merge/2
test_expect_success 'build graph from commits with append' '
cd "$TRASH_DIRECTORY/full" &&
git rev-parse merge/3 | git commit-graph write --stdin-commits --append &&
test_path_is_file $objdir/info/commit-graph &&
graph_read_expect "10" "generation_data extra_edges"
git -C full rev-parse merge/3 >in &&
git -C full commit-graph write --stdin-commits --append <in &&
test_path_is_file full/$objdir/info/commit-graph &&
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 2' full commits/8 merge/2
test_expect_success 'build graph using --reachable' '
cd "$TRASH_DIRECTORY/full" &&
git commit-graph write --reachable &&
test_path_is_file $objdir/info/commit-graph &&
graph_read_expect "11" "generation_data extra_edges"
git -C full commit-graph write --reachable &&
test_path_is_file full/$objdir/info/commit-graph &&
graph_read_expect -C full 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 2' full commits/8 merge/2
test_expect_success 'setup bare repo' '
cd "$TRASH_DIRECTORY" &&
git clone --bare --no-local full bare &&
cd bare &&
git config core.commitGraph true &&
baredir="./objects"
git clone --bare --no-local full bare
'
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
test_expect_success 'write graph in bare repo' '
cd "$TRASH_DIRECTORY/bare" &&
git commit-graph write &&
test_path_is_file $baredir/info/commit-graph &&
graph_read_expect "11" "generation_data extra_edges"
git -C bare commit-graph write &&
test_path_is_file bare/objects/info/commit-graph &&
graph_read_expect -C bare 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 2' bare commits/8 merge/2
test_expect_success 'perform fast-forward merge in full repo' '
cd "$TRASH_DIRECTORY/full" &&
git checkout -b merge-5-to-8 commits/5 &&
git merge commits/8 &&
git show-ref -s merge-5-to-8 >output &&
git show-ref -s commits/8 >expect &&
git -C full checkout -b merge-5-to-8 commits/5 &&
git -C full merge commits/8 &&
git -C full show-ref -s merge-5-to-8 >output &&
git -C full show-ref -s commits/8 >expect &&
test_cmp expect output
'
test_expect_success 'check that gc computes commit-graph' '
cd "$TRASH_DIRECTORY/full" &&
git commit --allow-empty -m "blank" &&
git commit-graph write --reachable &&
cp $objdir/info/commit-graph commit-graph-before-gc &&
git reset --hard HEAD~1 &&
git config gc.writeCommitGraph true &&
git gc &&
cp $objdir/info/commit-graph commit-graph-after-gc &&
test_commit -C full --no-tag blank &&
git -C full commit-graph write --reachable &&
cp full/$objdir/info/commit-graph commit-graph-before-gc &&
git -C full reset --hard HEAD~1 &&
test_config -C full gc.writeCommitGraph true &&
git -C full gc &&
cp full/$objdir/info/commit-graph commit-graph-after-gc &&
! test_cmp_bin commit-graph-before-gc commit-graph-after-gc &&
git commit-graph write --reachable &&
test_cmp_bin commit-graph-after-gc $objdir/info/commit-graph
git -C full commit-graph write --reachable &&
test_cmp_bin commit-graph-after-gc full/$objdir/info/commit-graph
'
test_expect_success 'replace-objects invalidates commit-graph' '
cd "$TRASH_DIRECTORY" &&
test_when_finished rm -rf 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' '
cd "$TRASH_DIRECTORY" &&
test_when_finished rm -rf 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' '
cd "$TRASH_DIRECTORY" &&
test_when_finished rm -rf 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' '
cd "$TRASH_DIRECTORY/full" &&
UNIX_EPOCH_ZERO="@0 +0000" &&
FUTURE_DATE="@4147483646 +0000" &&
rm -f .git/objects/info/commit-graph &&
test_commit --date "$FUTURE_DATE" future-1 &&
test_commit --date "$UNIX_EPOCH_ZERO" old-1 &&
git commit-graph write --reachable &&
test_commit --date "$FUTURE_DATE" future-2 &&
test_commit --date "$UNIX_EPOCH_ZERO" old-2 &&
git commit-graph write --reachable --split=no-merge &&
test_commit extra &&
git commit-graph write --reachable --split=no-merge &&
git commit-graph write --reachable &&
graph_read_expect 16 "generation_data generation_data_overflow extra_edges" &&
mv .git/objects/info/commit-graph commit-graph-upgraded &&
git commit-graph write --reachable &&
graph_read_expect 16 "generation_data generation_data_overflow extra_edges" &&
test_cmp .git/objects/info/commit-graph commit-graph-upgraded
rm -f full/.git/objects/info/commit-graph &&
test_commit -C full --date "$FUTURE_DATE" future-1 &&
test_commit -C full --date "$UNIX_EPOCH_ZERO" old-1 &&
git -C full commit-graph write --reachable &&
test_commit -C full --date "$FUTURE_DATE" future-2 &&
test_commit -C full --date "$UNIX_EPOCH_ZERO" old-2 &&
git -C full commit-graph write --reachable --split=no-merge &&
test_commit -C full extra &&
git -C full commit-graph write --reachable --split=no-merge &&
git -C full commit-graph write --reachable &&
graph_read_expect -C full 16 \
"generation_data generation_data_overflow extra_edges" &&
mv full/.git/objects/info/commit-graph commit-graph-upgraded &&
git -C full commit-graph write --reachable &&
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
@ -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.
test_expect_success 'git commit-graph verify' '
cd "$TRASH_DIRECTORY/full" &&
git rev-parse commits/8 | git -c commitGraph.generationVersion=1 commit-graph write --stdin-commits &&
git commit-graph verify >output &&
graph_read_expect 9 extra_edges 1
git -C full rev-parse commits/8 >in &&
git -C full -c commitGraph.generationVersion=1 commit-graph write \
--stdin-commits <in &&
git -C full commit-graph verify >output &&
graph_read_expect -C full 9 extra_edges 1
'
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))
corrupt_graph_setup() {
cd "$TRASH_DIRECTORY/full" &&
test_when_finished mv commit-graph-backup $objdir/info/commit-graph &&
cp $objdir/info/commit-graph commit-graph-backup &&
chmod u+w $objdir/info/commit-graph
test_when_finished mv commit-graph-backup full/$objdir/info/commit-graph &&
cp full/$objdir/info/commit-graph commit-graph-backup &&
chmod u+w full/$objdir/info/commit-graph
}
corrupt_graph_verify() {
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 &&
test_i18ngrep "$grepstr" err &&
if test "$2" != "no-copy"
then
cp $objdir/info/commit-graph commit-graph-pre-write-test
cp full/$objdir/info/commit-graph commit-graph-pre-write-test
fi &&
git status --short &&
GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE=true git commit-graph write &&
chmod u+w $objdir/info/commit-graph &&
git commit-graph verify
git -C full status --short &&
GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE=true git -C full commit-graph write &&
chmod u+w full/$objdir/info/commit-graph &&
git -C full commit-graph verify
}
# usage: corrupt_graph_and_verify <position> <data> <string> [<zero_pos>]
@ -527,24 +495,24 @@ corrupt_graph_and_verify() {
data="${2:-\0}"
grepstr=$3
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}} &&
printf "$data" | dd of="$objdir/info/commit-graph" bs=1 seek="$pos" conv=notrunc &&
dd of="$objdir/info/commit-graph" bs=1 seek="$zero_pos" if=/dev/null &&
test-tool genzeros $(($orig_size - $zero_pos)) >>"$objdir/info/commit-graph" &&
printf "$data" | dd of="full/$objdir/info/commit-graph" bs=1 seek="$pos" conv=notrunc &&
dd of="full/$objdir/info/commit-graph" bs=1 seek="$zero_pos" if=/dev/null &&
test-tool genzeros $(($orig_size - $zero_pos)) >>"full/$objdir/info/commit-graph" &&
corrupt_graph_verify "$grepstr"
}
test_expect_success POSIXPERM,SANITY 'detect permission problem' '
corrupt_graph_setup &&
chmod 000 $objdir/info/commit-graph &&
chmod 000 full/$objdir/info/commit-graph &&
corrupt_graph_verify "Could not open" "no-copy"
'
test_expect_success 'detect too small' '
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"
'
@ -655,33 +623,30 @@ test_expect_success 'detect incorrect chunk count' '
'
test_expect_success 'git fsck (checks commit-graph when config set to true)' '
cd "$TRASH_DIRECTORY/full" &&
git fsck &&
git -C full fsck &&
corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \
"incorrect checksum" &&
cp commit-graph-pre-write-test $objdir/info/commit-graph &&
test_must_fail git -c core.commitGraph=true fsck
cp commit-graph-pre-write-test full/$objdir/info/commit-graph &&
test_must_fail git -C full -c core.commitGraph=true fsck
'
test_expect_success 'git fsck (ignores commit-graph when config set to false)' '
cd "$TRASH_DIRECTORY/full" &&
git fsck &&
git -C full fsck &&
corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \
"incorrect checksum" &&
cp commit-graph-pre-write-test $objdir/info/commit-graph &&
git -c core.commitGraph=false fsck
cp commit-graph-pre-write-test full/$objdir/info/commit-graph &&
git -C full -c core.commitGraph=false fsck
'
test_expect_success 'git fsck (checks commit-graph when config unset)' '
cd "$TRASH_DIRECTORY/full" &&
test_when_finished "git config core.commitGraph true" &&
test_when_finished "git -C full config core.commitGraph true" &&
git fsck &&
git -C full fsck &&
corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \
"incorrect checksum" &&
test_unconfig core.commitGraph &&
cp commit-graph-pre-write-test $objdir/info/commit-graph &&
test_must_fail git fsck
test_unconfig -C full core.commitGraph &&
cp commit-graph-pre-write-test full/$objdir/info/commit-graph &&
test_must_fail git -C full fsck
'
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' '
objdir=".git/objects" &&
UNIX_EPOCH_ZERO="@0 +0000" &&
FUTURE_DATE="@2147483646 +0000" &&
cd "$TRASH_DIRECTORY" &&
mkdir repo &&
cd repo &&
git init &&
test_commit --date "$UNIX_EPOCH_ZERO" 1 &&
test_commit 2 &&
test_commit --date "$UNIX_EPOCH_ZERO" 3 &&
git commit-graph write --reachable &&
graph_read_expect 3 generation_data &&
test_commit --date "$FUTURE_DATE" 4 &&
test_commit 5 &&
test_commit --date "$UNIX_EPOCH_ZERO" 6 &&
git branch left &&
git reset --hard 3 &&
test_commit 7 &&
test_commit --date "$FUTURE_DATE" 8 &&
test_commit 9 &&
git branch right &&
git reset --hard 3 &&
test_merge M left right &&
git commit-graph write --reachable &&
graph_read_expect 10 "generation_data generation_data_overflow" &&
git commit-graph verify
git init repo &&
(
cd repo &&
test_commit --date "$UNIX_EPOCH_ZERO" 1 &&
test_commit 2 &&
test_commit --date "$UNIX_EPOCH_ZERO" 3 &&
git commit-graph write --reachable &&
graph_read_expect 3 generation_data &&
test_commit --date "$FUTURE_DATE" 4 &&
test_commit 5 &&
test_commit --date "$UNIX_EPOCH_ZERO" 6 &&
git branch left &&
git reset --hard 3 &&
test_commit 7 &&
test_commit --date "$FUTURE_DATE" 8 &&
test_commit 9 &&
git branch right &&
git reset --hard 3 &&
test_merge M left right &&
git commit-graph write --reachable &&
graph_read_expect 10 "generation_data generation_data_overflow" &&
git commit-graph verify
)
'
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
test_expect_success 'set up and verify repo with generation data overflow chunk' '
mkdir repo &&
cd repo &&
git init &&
test_commit --date "$UNIX_EPOCH_ZERO" 1 &&
test_commit 2 &&
test_commit --date "$UNIX_EPOCH_ZERO" 3 &&
git commit-graph write --reachable &&
graph_read_expect 3 generation_data &&
test_commit --date "$FUTURE_DATE" 4 &&
test_commit 5 &&
test_commit --date "$UNIX_EPOCH_ZERO" 6 &&
git branch left &&
git reset --hard 3 &&
test_commit 7 &&
test_commit --date "$FUTURE_DATE" 8 &&
test_commit 9 &&
git branch right &&
git reset --hard 3 &&
test_merge M left right &&
git commit-graph write --reachable &&
graph_read_expect 10 "generation_data generation_data_overflow" &&
git commit-graph verify
git init repo &&
(
cd repo &&
test_commit --date "$UNIX_EPOCH_ZERO" 1 &&
test_commit 2 &&
test_commit --date "$UNIX_EPOCH_ZERO" 3 &&
git commit-graph write --reachable &&
graph_read_expect 3 generation_data &&
test_commit --date "$FUTURE_DATE" 4 &&
test_commit 5 &&
test_commit --date "$UNIX_EPOCH_ZERO" 6 &&
git branch left &&
git reset --hard 3 &&
test_commit 7 &&
test_commit --date "$FUTURE_DATE" 8 &&
test_commit 9 &&
git branch right &&
git reset --hard 3 &&
test_merge M left right &&
git commit-graph write --reachable &&
graph_read_expect 10 "generation_data generation_data_overflow" &&
git commit-graph verify
)
'
graph_git_behavior 'overflow 2' repo left right
test_expect_success 'single commit with generation data exceeding UINT32_MAX' '
git init repo-uint32-max &&
cd repo-uint32-max &&
test_commit --date "@4294967297 +0000" 1 &&
git commit-graph write --reachable &&
graph_read_expect 1 "generation_data" &&
git commit-graph verify
test_commit -C repo-uint32-max --date "@4294967297 +0000" 1 &&
git -C repo-uint32-max commit-graph write --reachable &&
graph_read_expect -C repo-uint32-max 1 "generation_data" &&
git -C repo-uint32-max commit-graph verify
'
test_done

View File

@ -619,6 +619,12 @@ test_expect_success TTY 'create --quiet disables all bundle progress' '
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' '
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_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 "."' '
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_must_fail env GIT_AUTHOR_NAME=" .;<>" \
test_must_fail env GIT_AUTHOR_NAME=" ,;<>" \
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
# auto-detection could fail for other reasons.
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' '
clean_fake_sendmail &&
(echo "to@example.com" &&
echo ""
echo "my-message-id@example.com"
) | GIT_SEND_EMAIL_NOTTY=1 git send-email \
--smtp-server="$(pwd)/fake.sendmail" \
$patches \
2>errors &&
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' '
@ -659,7 +660,6 @@ test_expect_success $PREREQ 'clear message-id before parsing a new message' '
clean_fake_sendmail &&
echo true | write_script my-hooks/sendemail-validate &&
test_config core.hooksPath my-hooks &&
GIT_SEND_EMAIL_NOTTY=1 \
git send-email --validate --to=recipient@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
$patches $threaded_patches &&

View File

@ -1291,6 +1291,39 @@ test_cmp_rev () {
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
test_cmp_fspath () {
if test "x$1" = "x$2"