Compare commits
22 Commits
v2.32.0-rc
...
v2.32.0-rc
Author | SHA1 | Date | |
---|---|---|---|
4e42405f00 | |||
329d63e7be | |||
906fc557b7 | |||
eef814828f | |||
2c9f1bfdb4 | |||
1df046bcff | |||
5afd72a96f | |||
2f0ca41349 | |||
f4d715b0ac | |||
1accb34ce0 | |||
7d089fb9b7 | |||
ea08db7473 | |||
7cbc0455cc | |||
2815326f09 | |||
a96355d84c | |||
5d5b147345 | |||
d9929cbb08 | |||
53cb2103ce | |||
e2b05746e1 | |||
a185dd58ec | |||
5b719b7552 | |||
53753a37d0 |
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v2.32.0-rc1
|
||||
DEF_VER=v2.32.0-rc2
|
||||
|
||||
LF='
|
||||
'
|
||||
|
@ -212,8 +212,9 @@ static int create_default_files(const char *template_path,
|
||||
* values (since we've just potentially changed what's available on
|
||||
* disk).
|
||||
*/
|
||||
git_config_get_value("init.templatedir", &init_template_dir);
|
||||
git_config_get_pathname("init.templatedir", &init_template_dir);
|
||||
copy_templates(template_path, init_template_dir);
|
||||
free((char *)init_template_dir);
|
||||
git_config_clear();
|
||||
reset_shared_repository();
|
||||
git_config(git_default_config, NULL);
|
||||
|
@ -37,6 +37,134 @@
|
||||
#include "shallow.h"
|
||||
#include "promisor-remote.h"
|
||||
|
||||
/*
|
||||
* Objects we are going to pack are collected in the `to_pack` structure.
|
||||
* It contains an array (dynamically expanded) of the object data, and a map
|
||||
* that can resolve SHA1s to their position in the array.
|
||||
*/
|
||||
static struct packing_data to_pack;
|
||||
|
||||
static inline struct object_entry *oe_delta(
|
||||
const struct packing_data *pack,
|
||||
const struct object_entry *e)
|
||||
{
|
||||
if (!e->delta_idx)
|
||||
return NULL;
|
||||
if (e->ext_base)
|
||||
return &pack->ext_bases[e->delta_idx - 1];
|
||||
else
|
||||
return &pack->objects[e->delta_idx - 1];
|
||||
}
|
||||
|
||||
static inline unsigned long oe_delta_size(struct packing_data *pack,
|
||||
const struct object_entry *e)
|
||||
{
|
||||
if (e->delta_size_valid)
|
||||
return e->delta_size_;
|
||||
|
||||
/*
|
||||
* pack->delta_size[] can't be NULL because oe_set_delta_size()
|
||||
* must have been called when a new delta is saved with
|
||||
* oe_set_delta().
|
||||
* If oe_delta() returns NULL (i.e. default state, which means
|
||||
* delta_size_valid is also false), then the caller must never
|
||||
* call oe_delta_size().
|
||||
*/
|
||||
return pack->delta_size[e - pack->objects];
|
||||
}
|
||||
|
||||
unsigned long oe_get_size_slow(struct packing_data *pack,
|
||||
const struct object_entry *e);
|
||||
|
||||
static inline unsigned long oe_size(struct packing_data *pack,
|
||||
const struct object_entry *e)
|
||||
{
|
||||
if (e->size_valid)
|
||||
return e->size_;
|
||||
|
||||
return oe_get_size_slow(pack, e);
|
||||
}
|
||||
|
||||
static inline void oe_set_delta(struct packing_data *pack,
|
||||
struct object_entry *e,
|
||||
struct object_entry *delta)
|
||||
{
|
||||
if (delta)
|
||||
e->delta_idx = (delta - pack->objects) + 1;
|
||||
else
|
||||
e->delta_idx = 0;
|
||||
}
|
||||
|
||||
static inline struct object_entry *oe_delta_sibling(
|
||||
const struct packing_data *pack,
|
||||
const struct object_entry *e)
|
||||
{
|
||||
if (e->delta_sibling_idx)
|
||||
return &pack->objects[e->delta_sibling_idx - 1];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct object_entry *oe_delta_child(
|
||||
const struct packing_data *pack,
|
||||
const struct object_entry *e)
|
||||
{
|
||||
if (e->delta_child_idx)
|
||||
return &pack->objects[e->delta_child_idx - 1];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void oe_set_delta_child(struct packing_data *pack,
|
||||
struct object_entry *e,
|
||||
struct object_entry *delta)
|
||||
{
|
||||
if (delta)
|
||||
e->delta_child_idx = (delta - pack->objects) + 1;
|
||||
else
|
||||
e->delta_child_idx = 0;
|
||||
}
|
||||
|
||||
static inline void oe_set_delta_sibling(struct packing_data *pack,
|
||||
struct object_entry *e,
|
||||
struct object_entry *delta)
|
||||
{
|
||||
if (delta)
|
||||
e->delta_sibling_idx = (delta - pack->objects) + 1;
|
||||
else
|
||||
e->delta_sibling_idx = 0;
|
||||
}
|
||||
|
||||
static inline void oe_set_size(struct packing_data *pack,
|
||||
struct object_entry *e,
|
||||
unsigned long size)
|
||||
{
|
||||
if (size < pack->oe_size_limit) {
|
||||
e->size_ = size;
|
||||
e->size_valid = 1;
|
||||
} else {
|
||||
e->size_valid = 0;
|
||||
if (oe_get_size_slow(pack, e) != size)
|
||||
BUG("'size' is supposed to be the object size!");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void oe_set_delta_size(struct packing_data *pack,
|
||||
struct object_entry *e,
|
||||
unsigned long size)
|
||||
{
|
||||
if (size < pack->oe_delta_size_limit) {
|
||||
e->delta_size_ = size;
|
||||
e->delta_size_valid = 1;
|
||||
} else {
|
||||
packing_data_lock(pack);
|
||||
if (!pack->delta_size)
|
||||
ALLOC_ARRAY(pack->delta_size, pack->nr_alloc);
|
||||
packing_data_unlock(pack);
|
||||
|
||||
pack->delta_size[e - pack->objects] = size;
|
||||
e->delta_size_valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define IN_PACK(obj) oe_in_pack(&to_pack, obj)
|
||||
#define SIZE(obj) oe_size(&to_pack, obj)
|
||||
#define SET_SIZE(obj,size) oe_set_size(&to_pack, obj, size)
|
||||
@ -56,13 +184,6 @@ static const char *pack_usage[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* Objects we are going to pack are collected in the `to_pack` structure.
|
||||
* It contains an array (dynamically expanded) of the object data, and a map
|
||||
* that can resolve SHA1s to their position in the array.
|
||||
*/
|
||||
static struct packing_data to_pack;
|
||||
|
||||
static struct pack_idx_entry **written_list;
|
||||
static uint32_t nr_result, nr_written, nr_seen;
|
||||
static struct bitmap_index *bitmap_git;
|
||||
@ -301,6 +422,17 @@ static void copy_pack_data(struct hashfile *f,
|
||||
}
|
||||
}
|
||||
|
||||
static inline int oe_size_greater_than(struct packing_data *pack,
|
||||
const struct object_entry *lhs,
|
||||
unsigned long rhs)
|
||||
{
|
||||
if (lhs->size_valid)
|
||||
return lhs->size_ > rhs;
|
||||
if (rhs < pack->oe_size_limit) /* rhs < 2^x <= lhs ? */
|
||||
return 1;
|
||||
return oe_get_size_slow(pack, lhs) > rhs;
|
||||
}
|
||||
|
||||
/* Return 0 if we will bust the pack-size limit */
|
||||
static unsigned long write_no_reuse_object(struct hashfile *f, struct object_entry *entry,
|
||||
unsigned long limit, int usable_delta)
|
||||
@ -642,6 +774,14 @@ static int mark_tagged(const char *path, const struct object_id *oid, int flag,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned char oe_layer(struct packing_data *pack,
|
||||
struct object_entry *e)
|
||||
{
|
||||
if (!pack->layer)
|
||||
return 0;
|
||||
return pack->layer[e - pack->objects];
|
||||
}
|
||||
|
||||
static inline void add_to_write_order(struct object_entry **wo,
|
||||
unsigned int *endp,
|
||||
struct object_entry *e)
|
||||
@ -2231,6 +2371,26 @@ static pthread_mutex_t progress_mutex;
|
||||
* progress_mutex for protection.
|
||||
*/
|
||||
|
||||
static inline int oe_size_less_than(struct packing_data *pack,
|
||||
const struct object_entry *lhs,
|
||||
unsigned long rhs)
|
||||
{
|
||||
if (lhs->size_valid)
|
||||
return lhs->size_ < rhs;
|
||||
if (rhs < pack->oe_size_limit) /* rhs < 2^x <= lhs ? */
|
||||
return 0;
|
||||
return oe_get_size_slow(pack, lhs) < rhs;
|
||||
}
|
||||
|
||||
static inline void oe_set_tree_depth(struct packing_data *pack,
|
||||
struct object_entry *e,
|
||||
unsigned int tree_depth)
|
||||
{
|
||||
if (!pack->tree_depth)
|
||||
CALLOC_ARRAY(pack->tree_depth, pack->nr_alloc);
|
||||
pack->tree_depth[e - pack->objects] = tree_depth;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the size of the object without doing any delta
|
||||
* reconstruction (so non-deltas are true object sizes, but deltas
|
||||
|
3
dir.c
3
dir.c
@ -59,8 +59,7 @@ void dir_init(struct dir_struct *dir)
|
||||
memset(dir, 0, sizeof(*dir));
|
||||
}
|
||||
|
||||
struct dirent *
|
||||
readdir_skip_dot_and_dotdot(DIR *dirp)
|
||||
struct dirent *readdir_skip_dot_and_dotdot(DIR *dirp)
|
||||
{
|
||||
struct dirent *e;
|
||||
|
||||
|
@ -219,8 +219,18 @@ sub system_or_msg {
|
||||
my $exit_code = $? >> 8;
|
||||
return unless $signalled or $exit_code;
|
||||
|
||||
my @sprintf_args = ($args->[0], $exit_code);
|
||||
if (defined $msg) {
|
||||
# Quiet the 'redundant' warning category, except we
|
||||
# need to support down to Perl 5.8, so we can't do a
|
||||
# "no warnings 'redundant'", since that category was
|
||||
# introduced in perl 5.22, and asking for it will die
|
||||
# on older perls.
|
||||
no warnings;
|
||||
return sprintf($msg, @sprintf_args);
|
||||
}
|
||||
return sprintf(__("fatal: command '%s' died with exit code %d"),
|
||||
$args->[0], $exit_code);
|
||||
@sprintf_args);
|
||||
}
|
||||
|
||||
sub system_or_die {
|
||||
@ -1949,7 +1959,8 @@ sub validate_patch {
|
||||
my ($fn, $xfer_encoding) = @_;
|
||||
|
||||
if ($repo) {
|
||||
my $validate_hook = catfile($repo->hooks_path(),
|
||||
my $hooks_path = $repo->command_oneline('rev-parse', '--git-path', 'hooks');
|
||||
my $validate_hook = catfile($hooks_path,
|
||||
'sendemail-validate');
|
||||
my $hook_error;
|
||||
if (-x $validate_hook) {
|
||||
|
159
pack-objects.h
159
pack-objects.h
@ -268,152 +268,10 @@ static inline void oe_set_in_pack(struct packing_data *pack,
|
||||
pack->in_pack[e - pack->objects] = p;
|
||||
}
|
||||
|
||||
static inline struct object_entry *oe_delta(
|
||||
const struct packing_data *pack,
|
||||
const struct object_entry *e)
|
||||
{
|
||||
if (!e->delta_idx)
|
||||
return NULL;
|
||||
if (e->ext_base)
|
||||
return &pack->ext_bases[e->delta_idx - 1];
|
||||
else
|
||||
return &pack->objects[e->delta_idx - 1];
|
||||
}
|
||||
|
||||
static inline void oe_set_delta(struct packing_data *pack,
|
||||
struct object_entry *e,
|
||||
struct object_entry *delta)
|
||||
{
|
||||
if (delta)
|
||||
e->delta_idx = (delta - pack->objects) + 1;
|
||||
else
|
||||
e->delta_idx = 0;
|
||||
}
|
||||
|
||||
void oe_set_delta_ext(struct packing_data *pack,
|
||||
struct object_entry *e,
|
||||
const struct object_id *oid);
|
||||
|
||||
static inline struct object_entry *oe_delta_child(
|
||||
const struct packing_data *pack,
|
||||
const struct object_entry *e)
|
||||
{
|
||||
if (e->delta_child_idx)
|
||||
return &pack->objects[e->delta_child_idx - 1];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void oe_set_delta_child(struct packing_data *pack,
|
||||
struct object_entry *e,
|
||||
struct object_entry *delta)
|
||||
{
|
||||
if (delta)
|
||||
e->delta_child_idx = (delta - pack->objects) + 1;
|
||||
else
|
||||
e->delta_child_idx = 0;
|
||||
}
|
||||
|
||||
static inline struct object_entry *oe_delta_sibling(
|
||||
const struct packing_data *pack,
|
||||
const struct object_entry *e)
|
||||
{
|
||||
if (e->delta_sibling_idx)
|
||||
return &pack->objects[e->delta_sibling_idx - 1];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void oe_set_delta_sibling(struct packing_data *pack,
|
||||
struct object_entry *e,
|
||||
struct object_entry *delta)
|
||||
{
|
||||
if (delta)
|
||||
e->delta_sibling_idx = (delta - pack->objects) + 1;
|
||||
else
|
||||
e->delta_sibling_idx = 0;
|
||||
}
|
||||
|
||||
unsigned long oe_get_size_slow(struct packing_data *pack,
|
||||
const struct object_entry *e);
|
||||
static inline unsigned long oe_size(struct packing_data *pack,
|
||||
const struct object_entry *e)
|
||||
{
|
||||
if (e->size_valid)
|
||||
return e->size_;
|
||||
|
||||
return oe_get_size_slow(pack, e);
|
||||
}
|
||||
|
||||
static inline int oe_size_less_than(struct packing_data *pack,
|
||||
const struct object_entry *lhs,
|
||||
unsigned long rhs)
|
||||
{
|
||||
if (lhs->size_valid)
|
||||
return lhs->size_ < rhs;
|
||||
if (rhs < pack->oe_size_limit) /* rhs < 2^x <= lhs ? */
|
||||
return 0;
|
||||
return oe_get_size_slow(pack, lhs) < rhs;
|
||||
}
|
||||
|
||||
static inline int oe_size_greater_than(struct packing_data *pack,
|
||||
const struct object_entry *lhs,
|
||||
unsigned long rhs)
|
||||
{
|
||||
if (lhs->size_valid)
|
||||
return lhs->size_ > rhs;
|
||||
if (rhs < pack->oe_size_limit) /* rhs < 2^x <= lhs ? */
|
||||
return 1;
|
||||
return oe_get_size_slow(pack, lhs) > rhs;
|
||||
}
|
||||
|
||||
static inline void oe_set_size(struct packing_data *pack,
|
||||
struct object_entry *e,
|
||||
unsigned long size)
|
||||
{
|
||||
if (size < pack->oe_size_limit) {
|
||||
e->size_ = size;
|
||||
e->size_valid = 1;
|
||||
} else {
|
||||
e->size_valid = 0;
|
||||
if (oe_get_size_slow(pack, e) != size)
|
||||
BUG("'size' is supposed to be the object size!");
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned long oe_delta_size(struct packing_data *pack,
|
||||
const struct object_entry *e)
|
||||
{
|
||||
if (e->delta_size_valid)
|
||||
return e->delta_size_;
|
||||
|
||||
/*
|
||||
* pack->delta_size[] can't be NULL because oe_set_delta_size()
|
||||
* must have been called when a new delta is saved with
|
||||
* oe_set_delta().
|
||||
* If oe_delta() returns NULL (i.e. default state, which means
|
||||
* delta_size_valid is also false), then the caller must never
|
||||
* call oe_delta_size().
|
||||
*/
|
||||
return pack->delta_size[e - pack->objects];
|
||||
}
|
||||
|
||||
static inline void oe_set_delta_size(struct packing_data *pack,
|
||||
struct object_entry *e,
|
||||
unsigned long size)
|
||||
{
|
||||
if (size < pack->oe_delta_size_limit) {
|
||||
e->delta_size_ = size;
|
||||
e->delta_size_valid = 1;
|
||||
} else {
|
||||
packing_data_lock(pack);
|
||||
if (!pack->delta_size)
|
||||
ALLOC_ARRAY(pack->delta_size, pack->nr_alloc);
|
||||
packing_data_unlock(pack);
|
||||
|
||||
pack->delta_size[e - pack->objects] = size;
|
||||
e->delta_size_valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned int oe_tree_depth(struct packing_data *pack,
|
||||
struct object_entry *e)
|
||||
{
|
||||
@ -422,23 +280,6 @@ static inline unsigned int oe_tree_depth(struct packing_data *pack,
|
||||
return pack->tree_depth[e - pack->objects];
|
||||
}
|
||||
|
||||
static inline void oe_set_tree_depth(struct packing_data *pack,
|
||||
struct object_entry *e,
|
||||
unsigned int tree_depth)
|
||||
{
|
||||
if (!pack->tree_depth)
|
||||
CALLOC_ARRAY(pack->tree_depth, pack->nr_alloc);
|
||||
pack->tree_depth[e - pack->objects] = tree_depth;
|
||||
}
|
||||
|
||||
static inline unsigned char oe_layer(struct packing_data *pack,
|
||||
struct object_entry *e)
|
||||
{
|
||||
if (!pack->layer)
|
||||
return 0;
|
||||
return pack->layer[e - pack->objects];
|
||||
}
|
||||
|
||||
static inline void oe_set_layer(struct packing_data *pack,
|
||||
struct object_entry *e,
|
||||
unsigned char layer)
|
||||
|
13
perl/Git.pm
13
perl/Git.pm
@ -619,19 +619,6 @@ Return path to the git repository. Must be called on a repository instance.
|
||||
|
||||
sub repo_path { $_[0]->{opts}->{Repository} }
|
||||
|
||||
=item hooks_path ()
|
||||
|
||||
Return path to the hooks directory. Must be called on a repository instance.
|
||||
|
||||
=cut
|
||||
|
||||
sub hooks_path {
|
||||
my ($self) = @_;
|
||||
|
||||
my $dir = $self->command_oneline('rev-parse', '--git-path', 'hooks');
|
||||
my $abs = abs_path($dir);
|
||||
return $abs;
|
||||
}
|
||||
|
||||
=item wc_path ()
|
||||
|
||||
|
@ -186,21 +186,33 @@ test_expect_success 'init with --template (blank)' '
|
||||
test_path_is_missing template-blank/.git/info/exclude
|
||||
'
|
||||
|
||||
init_no_templatedir_env () {
|
||||
(
|
||||
sane_unset GIT_TEMPLATE_DIR &&
|
||||
NO_SET_GIT_TEMPLATE_DIR=t &&
|
||||
export NO_SET_GIT_TEMPLATE_DIR &&
|
||||
git init "$1"
|
||||
)
|
||||
}
|
||||
|
||||
test_expect_success 'init with init.templatedir set' '
|
||||
mkdir templatedir-source &&
|
||||
echo Content >templatedir-source/file &&
|
||||
test_config_global init.templatedir "${HOME}/templatedir-source" &&
|
||||
(
|
||||
mkdir templatedir-set &&
|
||||
cd templatedir-set &&
|
||||
sane_unset GIT_TEMPLATE_DIR &&
|
||||
NO_SET_GIT_TEMPLATE_DIR=t &&
|
||||
export NO_SET_GIT_TEMPLATE_DIR &&
|
||||
git init
|
||||
) &&
|
||||
|
||||
init_no_templatedir_env templatedir-set &&
|
||||
test_cmp templatedir-source/file templatedir-set/.git/file
|
||||
'
|
||||
|
||||
test_expect_success 'init with init.templatedir using ~ expansion' '
|
||||
mkdir -p templatedir-source &&
|
||||
echo Content >templatedir-source/file &&
|
||||
test_config_global init.templatedir "~/templatedir-source" &&
|
||||
|
||||
init_no_templatedir_env templatedir-expansion &&
|
||||
test_cmp templatedir-source/file templatedir-expansion/.git/file
|
||||
'
|
||||
|
||||
test_expect_success 'init --bare/--shared overrides system/global config' '
|
||||
test_config_global core.bare false &&
|
||||
test_config_global core.sharedRepository 0640 &&
|
||||
|
@ -106,18 +106,18 @@ init_repos () {
|
||||
run_on_sparse () {
|
||||
(
|
||||
cd sparse-checkout &&
|
||||
"$@" >../sparse-checkout-out 2>../sparse-checkout-err
|
||||
GIT_PROGRESS_DELAY=100000 "$@" >../sparse-checkout-out 2>../sparse-checkout-err
|
||||
) &&
|
||||
(
|
||||
cd sparse-index &&
|
||||
"$@" >../sparse-index-out 2>../sparse-index-err
|
||||
GIT_PROGRESS_DELAY=100000 "$@" >../sparse-index-out 2>../sparse-index-err
|
||||
)
|
||||
}
|
||||
|
||||
run_on_all () {
|
||||
(
|
||||
cd full-checkout &&
|
||||
"$@" >../full-checkout-out 2>../full-checkout-err
|
||||
GIT_PROGRESS_DELAY=100000 "$@" >../full-checkout-out 2>../full-checkout-err
|
||||
) &&
|
||||
run_on_sparse "$@"
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ do
|
||||
|
||||
test_expect_success "$mode checkout" '
|
||||
repo=various_$mode &&
|
||||
cp -R various $repo &&
|
||||
cp -R -P various $repo &&
|
||||
|
||||
# The just copied files have more recent timestamps than their
|
||||
# associated index entries. So refresh the cached timestamps
|
||||
|
@ -539,7 +539,7 @@ test_expect_success $PREREQ "--validate respects relative core.hooksPath path" '
|
||||
test_path_is_file my-hooks.ran &&
|
||||
cat >expect <<-EOF &&
|
||||
fatal: longline.patch: rejected by sendemail-validate hook
|
||||
fatal: command '"'"'$(pwd)/my-hooks/sendemail-validate'"'"' died with exit code 1
|
||||
fatal: command '"'"'my-hooks/sendemail-validate'"'"' died with exit code 1
|
||||
warning: no patches were sent
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
@ -644,14 +644,33 @@ test_expect_success $PREREQ 'In-Reply-To with --chain-reply-to' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_set_editor "$(pwd)/fake-editor"
|
||||
|
||||
test_expect_success $PREREQ 'setup erroring fake editor' '
|
||||
write_script fake-editor <<-\EOF
|
||||
echo >&2 "I am about to error"
|
||||
exit 1
|
||||
EOF
|
||||
'
|
||||
|
||||
test_expect_success $PREREQ 'fake editor dies with error' '
|
||||
clean_fake_sendmail &&
|
||||
test_must_fail git send-email \
|
||||
--compose --subject foo \
|
||||
--from="Example <nobody@example.com>" \
|
||||
--to=nobody@example.com \
|
||||
--smtp-server="$(pwd)/fake.sendmail" \
|
||||
$patches 2>err &&
|
||||
grep "I am about to error" err &&
|
||||
grep "the editor exited uncleanly, aborting everything" err
|
||||
'
|
||||
|
||||
test_expect_success $PREREQ 'setup fake editor' '
|
||||
write_script fake-editor <<-\EOF
|
||||
echo fake edit >>"$1"
|
||||
EOF
|
||||
'
|
||||
|
||||
test_set_editor "$(pwd)/fake-editor"
|
||||
|
||||
test_expect_success $PREREQ '--compose works' '
|
||||
clean_fake_sendmail &&
|
||||
git send-email \
|
||||
|
Reference in New Issue
Block a user