Merge branch 'maint'
* maint: git-send-email.txt: move --format-patch paragraph to a proper location git-shortlog.txt: improve documentation about .mailmap files pretty: support multiline subjects with format: pretty: factor out format_subject() pretty: factor out skip_empty_lines() merge-file: handle freopen() failure daemon: cleanup: factor out xstrdup_tolower() daemon: cleanup: replace loop with if daemon: handle freopen() failure describe: Avoid unnecessary warning when using --all
This commit is contained in:
commit
159c88e5ae
@ -197,12 +197,6 @@ Administering
|
|||||||
--[no-]validate::
|
--[no-]validate::
|
||||||
Perform sanity checks on patches.
|
Perform sanity checks on patches.
|
||||||
Currently, validation means the following:
|
Currently, validation means the following:
|
||||||
|
|
||||||
--[no-]format-patch::
|
|
||||||
When an argument may be understood either as a reference or as a file name,
|
|
||||||
choose to understand it as a format-patch argument ('--format-patch')
|
|
||||||
or as a file name ('--no-format-patch'). By default, when such a conflict
|
|
||||||
occurs, git send-email will fail.
|
|
||||||
+
|
+
|
||||||
--
|
--
|
||||||
* Warn of patches that contain lines longer than 998 characters; this
|
* Warn of patches that contain lines longer than 998 characters; this
|
||||||
@ -212,6 +206,12 @@ Administering
|
|||||||
Default is the value of 'sendemail.validate'; if this is not set,
|
Default is the value of 'sendemail.validate'; if this is not set,
|
||||||
default to '--validate'.
|
default to '--validate'.
|
||||||
|
|
||||||
|
--[no-]format-patch::
|
||||||
|
When an argument may be understood either as a reference or as a file name,
|
||||||
|
choose to understand it as a format-patch argument ('--format-patch')
|
||||||
|
or as a file name ('--no-format-patch'). By default, when such a conflict
|
||||||
|
occurs, git send-email will fail.
|
||||||
|
|
||||||
|
|
||||||
CONFIGURATION
|
CONFIGURATION
|
||||||
-------------
|
-------------
|
||||||
|
@ -48,15 +48,41 @@ OPTIONS
|
|||||||
FILES
|
FILES
|
||||||
-----
|
-----
|
||||||
|
|
||||||
If the file `.mailmap` exists, it will be used for mapping author
|
If a file `.mailmap` exists at the toplevel of the repository,
|
||||||
email addresses to a real author name. One mapping per line, first
|
it is used to map an author email address to a canonical real name. This
|
||||||
the author name followed by the email address enclosed by
|
can be used to coalesce together commits by the same person where their
|
||||||
'<' and '>'. Use hash '#' for comments. Example:
|
name was spelled differently (whether with the same email address or
|
||||||
|
not).
|
||||||
|
|
||||||
|
Each line in the file consists, in this order, of the canonical real name
|
||||||
|
of an author, whitespace, and an email address (enclosed by '<' and '>')
|
||||||
|
to map to the name. Use hash '#' for comments, either on their own line,
|
||||||
|
or after the email address.
|
||||||
|
|
||||||
|
A canonical name may appear in more than one line, associated with
|
||||||
|
different email addresses, but it doesn't make sense for a given address
|
||||||
|
to appear more than once (if that happens, a later line overrides the
|
||||||
|
earlier ones).
|
||||||
|
|
||||||
|
So, for example, if your history contains commits by two authors, Jane
|
||||||
|
and Joe, whose names appear in the repository under several forms:
|
||||||
|
|
||||||
------------
|
------------
|
||||||
# Keep alphabetized
|
Joe Developer <joe@example.com>
|
||||||
Adam Morrow <adam@localhost.localdomain>
|
Joe R. Developer <joe@example.com>
|
||||||
Eve Jones <eve@laptop.(none)>
|
Jane Doe <jane@example.com>
|
||||||
|
Jane Doe <jane@laptop.(none)>
|
||||||
|
Jane D. <jane@desktop.(none)>
|
||||||
|
------------
|
||||||
|
|
||||||
|
Then, supposing Joe wants his middle name initial used, and Jane prefers
|
||||||
|
her family name fully spelled out, a proper `.mailmap` file would look like:
|
||||||
|
|
||||||
|
------------
|
||||||
|
# Note how we don't need an entry for <jane@laptop.(none)>, because the
|
||||||
|
# real name of that author is correct already, and coalesced directly.
|
||||||
|
Jane Doe <jane@desktop.(none)>
|
||||||
|
Joe R. Developer <joe@random.com>
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Author
|
Author
|
||||||
|
@ -158,7 +158,7 @@ static void display_name(struct commit_name *n)
|
|||||||
n->tag = lookup_tag(n->sha1);
|
n->tag = lookup_tag(n->sha1);
|
||||||
if (!n->tag || parse_tag(n->tag) || !n->tag->tag)
|
if (!n->tag || parse_tag(n->tag) || !n->tag->tag)
|
||||||
die("annotated tag %s not available", n->path);
|
die("annotated tag %s not available", n->path);
|
||||||
if (strcmp(n->tag->tag, n->path))
|
if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
|
||||||
warning("tag '%s' is really '%s' here", n->tag->tag, n->path);
|
warning("tag '%s' is really '%s' here", n->tag->tag, n->path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,8 +51,11 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
|
|||||||
argc = parse_options(argc, argv, options, merge_file_usage, 0);
|
argc = parse_options(argc, argv, options, merge_file_usage, 0);
|
||||||
if (argc != 3)
|
if (argc != 3)
|
||||||
usage_with_options(merge_file_usage, options);
|
usage_with_options(merge_file_usage, options);
|
||||||
if (quiet)
|
if (quiet) {
|
||||||
freopen("/dev/null", "w", stderr);
|
if (!freopen("/dev/null", "w", stderr))
|
||||||
|
return error("failed to redirect stderr to /dev/null: "
|
||||||
|
"%s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
if (!names[i])
|
if (!names[i])
|
||||||
|
48
daemon.c
48
daemon.c
@ -150,7 +150,6 @@ static char *path_ok(char *directory)
|
|||||||
{
|
{
|
||||||
static char rpath[PATH_MAX];
|
static char rpath[PATH_MAX];
|
||||||
static char interp_path[PATH_MAX];
|
static char interp_path[PATH_MAX];
|
||||||
int retried_path = 0;
|
|
||||||
char *path;
|
char *path;
|
||||||
char *dir;
|
char *dir;
|
||||||
|
|
||||||
@ -219,22 +218,15 @@ static char *path_ok(char *directory)
|
|||||||
dir = rpath;
|
dir = rpath;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
|
||||||
path = enter_repo(dir, strict_paths);
|
path = enter_repo(dir, strict_paths);
|
||||||
if (path)
|
if (!path && base_path && base_path_relaxed) {
|
||||||
break;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we fail and base_path_relaxed is enabled, try without
|
* if we fail and base_path_relaxed is enabled, try without
|
||||||
* prefixing the base path
|
* prefixing the base path
|
||||||
*/
|
*/
|
||||||
if (base_path && base_path_relaxed && !retried_path) {
|
|
||||||
dir = directory;
|
dir = directory;
|
||||||
retried_path = 1;
|
path = enter_repo(dir, strict_paths);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
} while (1);
|
|
||||||
|
|
||||||
if (!path) {
|
if (!path) {
|
||||||
logerror("'%s': unable to chdir or not a git archive", dir);
|
logerror("'%s': unable to chdir or not a git archive", dir);
|
||||||
@ -405,6 +397,14 @@ static void make_service_overridable(const char *name, int ena)
|
|||||||
die("No such service %s", name);
|
die("No such service %s", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *xstrdup_tolower(const char *str)
|
||||||
|
{
|
||||||
|
char *p, *dup = xstrdup(str);
|
||||||
|
for (p = dup; *p; p++)
|
||||||
|
*p = tolower(*p);
|
||||||
|
return dup;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Separate the "extra args" information as supplied by the client connection.
|
* Separate the "extra args" information as supplied by the client connection.
|
||||||
*/
|
*/
|
||||||
@ -413,7 +413,6 @@ static void parse_extra_args(char *extra_args, int buflen)
|
|||||||
char *val;
|
char *val;
|
||||||
int vallen;
|
int vallen;
|
||||||
char *end = extra_args + buflen;
|
char *end = extra_args + buflen;
|
||||||
char *hp;
|
|
||||||
|
|
||||||
while (extra_args < end && *extra_args) {
|
while (extra_args < end && *extra_args) {
|
||||||
saw_extended_args = 1;
|
saw_extended_args = 1;
|
||||||
@ -431,7 +430,7 @@ static void parse_extra_args(char *extra_args, int buflen)
|
|||||||
tcp_port = xstrdup(port);
|
tcp_port = xstrdup(port);
|
||||||
}
|
}
|
||||||
free(hostname);
|
free(hostname);
|
||||||
hostname = xstrdup(host);
|
hostname = xstrdup_tolower(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On to the next one */
|
/* On to the next one */
|
||||||
@ -439,20 +438,11 @@ static void parse_extra_args(char *extra_args, int buflen)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Replace literal host with lowercase-ized hostname.
|
|
||||||
*/
|
|
||||||
hp = hostname;
|
|
||||||
if (!hp)
|
|
||||||
return;
|
|
||||||
for ( ; *hp; hp++)
|
|
||||||
*hp = tolower(*hp);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Locate canonical hostname and its IP address.
|
* Locate canonical hostname and its IP address.
|
||||||
*/
|
*/
|
||||||
|
if (hostname) {
|
||||||
#ifndef NO_IPV6
|
#ifndef NO_IPV6
|
||||||
{
|
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
struct addrinfo *ai, *ai0;
|
struct addrinfo *ai, *ai0;
|
||||||
int gai;
|
int gai;
|
||||||
@ -476,9 +466,7 @@ static void parse_extra_args(char *extra_args, int buflen)
|
|||||||
}
|
}
|
||||||
freeaddrinfo(ai0);
|
freeaddrinfo(ai0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
{
|
|
||||||
struct hostent *hent;
|
struct hostent *hent;
|
||||||
struct sockaddr_in sa;
|
struct sockaddr_in sa;
|
||||||
char **ap;
|
char **ap;
|
||||||
@ -499,8 +487,8 @@ static void parse_extra_args(char *extra_args, int buflen)
|
|||||||
canon_hostname = xstrdup(hent->h_name);
|
canon_hostname = xstrdup(hent->h_name);
|
||||||
free(ip_address);
|
free(ip_address);
|
||||||
ip_address = xstrdup(addrbuf);
|
ip_address = xstrdup(addrbuf);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -953,11 +941,7 @@ int main(int argc, char **argv)
|
|||||||
char *arg = argv[i];
|
char *arg = argv[i];
|
||||||
|
|
||||||
if (!prefixcmp(arg, "--listen=")) {
|
if (!prefixcmp(arg, "--listen=")) {
|
||||||
char *p = arg + 9;
|
listen_addr = xstrdup_tolower(arg + 9);
|
||||||
char *ph = listen_addr = xmalloc(strlen(arg + 9) + 1);
|
|
||||||
while (*p)
|
|
||||||
*ph++ = tolower(*p++);
|
|
||||||
*ph = 0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!prefixcmp(arg, "--port=")) {
|
if (!prefixcmp(arg, "--port=")) {
|
||||||
@ -1118,7 +1102,9 @@ int main(int argc, char **argv)
|
|||||||
struct sockaddr *peer = (struct sockaddr *)&ss;
|
struct sockaddr *peer = (struct sockaddr *)&ss;
|
||||||
socklen_t slen = sizeof(ss);
|
socklen_t slen = sizeof(ss);
|
||||||
|
|
||||||
freopen("/dev/null", "w", stderr);
|
if (!freopen("/dev/null", "w", stderr))
|
||||||
|
die("failed to redirect stderr to /dev/null: %s",
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
if (getpeername(0, peer, &slen))
|
if (getpeername(0, peer, &slen))
|
||||||
peer = NULL;
|
peer = NULL;
|
||||||
|
119
pretty.c
119
pretty.c
@ -181,6 +181,20 @@ static int is_empty_line(const char *line, int *len_p)
|
|||||||
return !len;
|
return !len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *skip_empty_lines(const char *msg)
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
int linelen = get_one_line(msg);
|
||||||
|
int ll = linelen;
|
||||||
|
if (!linelen)
|
||||||
|
break;
|
||||||
|
if (!is_empty_line(msg, &ll))
|
||||||
|
break;
|
||||||
|
msg += linelen;
|
||||||
|
}
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb,
|
static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb,
|
||||||
const struct commit *commit, int abbrev)
|
const struct commit *commit, int abbrev)
|
||||||
{
|
{
|
||||||
@ -410,13 +424,15 @@ struct chunk {
|
|||||||
struct format_commit_context {
|
struct format_commit_context {
|
||||||
const struct commit *commit;
|
const struct commit *commit;
|
||||||
enum date_mode dmode;
|
enum date_mode dmode;
|
||||||
|
unsigned commit_header_parsed:1;
|
||||||
|
unsigned commit_message_parsed:1;
|
||||||
|
|
||||||
/* These offsets are relative to the start of the commit message. */
|
/* These offsets are relative to the start of the commit message. */
|
||||||
int commit_header_parsed;
|
|
||||||
struct chunk subject;
|
|
||||||
struct chunk author;
|
struct chunk author;
|
||||||
struct chunk committer;
|
struct chunk committer;
|
||||||
struct chunk encoding;
|
struct chunk encoding;
|
||||||
|
size_t message_off;
|
||||||
|
size_t subject_off;
|
||||||
size_t body_off;
|
size_t body_off;
|
||||||
|
|
||||||
/* The following ones are relative to the result struct strbuf. */
|
/* The following ones are relative to the result struct strbuf. */
|
||||||
@ -446,23 +462,14 @@ static void parse_commit_header(struct format_commit_context *context)
|
|||||||
{
|
{
|
||||||
const char *msg = context->commit->buffer;
|
const char *msg = context->commit->buffer;
|
||||||
int i;
|
int i;
|
||||||
enum { HEADER, SUBJECT, BODY } state;
|
|
||||||
|
|
||||||
for (i = 0, state = HEADER; msg[i] && state < BODY; i++) {
|
for (i = 0; msg[i]; i++) {
|
||||||
int eol;
|
int eol;
|
||||||
for (eol = i; msg[eol] && msg[eol] != '\n'; eol++)
|
for (eol = i; msg[eol] && msg[eol] != '\n'; eol++)
|
||||||
; /* do nothing */
|
; /* do nothing */
|
||||||
|
|
||||||
if (state == SUBJECT) {
|
|
||||||
context->subject.off = i;
|
|
||||||
context->subject.len = eol - i;
|
|
||||||
i = eol;
|
|
||||||
}
|
|
||||||
if (i == eol) {
|
if (i == eol) {
|
||||||
state++;
|
break;
|
||||||
/* strip empty lines */
|
|
||||||
while (msg[eol] == '\n' && msg[eol + 1] == '\n')
|
|
||||||
eol++;
|
|
||||||
} else if (!prefixcmp(msg + i, "author ")) {
|
} else if (!prefixcmp(msg + i, "author ")) {
|
||||||
context->author.off = i + 7;
|
context->author.off = i + 7;
|
||||||
context->author.len = eol - i - 7;
|
context->author.len = eol - i - 7;
|
||||||
@ -474,13 +481,50 @@ static void parse_commit_header(struct format_commit_context *context)
|
|||||||
context->encoding.len = eol - i - 9;
|
context->encoding.len = eol - i - 9;
|
||||||
}
|
}
|
||||||
i = eol;
|
i = eol;
|
||||||
if (!msg[i])
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
context->body_off = i;
|
context->message_off = i;
|
||||||
context->commit_header_parsed = 1;
|
context->commit_header_parsed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *format_subject(struct strbuf *sb, const char *msg,
|
||||||
|
const char *line_separator)
|
||||||
|
{
|
||||||
|
int first = 1;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
const char *line = msg;
|
||||||
|
int linelen = get_one_line(line);
|
||||||
|
|
||||||
|
msg += linelen;
|
||||||
|
if (!linelen || is_empty_line(line, &linelen))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!sb)
|
||||||
|
continue;
|
||||||
|
strbuf_grow(sb, linelen + 2);
|
||||||
|
if (!first)
|
||||||
|
strbuf_addstr(sb, line_separator);
|
||||||
|
strbuf_add(sb, line, linelen);
|
||||||
|
first = 0;
|
||||||
|
}
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_commit_message(struct format_commit_context *c)
|
||||||
|
{
|
||||||
|
const char *msg = c->commit->buffer + c->message_off;
|
||||||
|
const char *start = c->commit->buffer;
|
||||||
|
|
||||||
|
msg = skip_empty_lines(msg);
|
||||||
|
c->subject_off = msg - start;
|
||||||
|
|
||||||
|
msg = format_subject(NULL, msg, NULL);
|
||||||
|
msg = skip_empty_lines(msg);
|
||||||
|
c->body_off = msg - start;
|
||||||
|
|
||||||
|
c->commit_message_parsed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void format_decoration(struct strbuf *sb, const struct commit *commit)
|
static void format_decoration(struct strbuf *sb, const struct commit *commit)
|
||||||
{
|
{
|
||||||
struct name_decoration *d;
|
struct name_decoration *d;
|
||||||
@ -600,9 +644,6 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
|
|||||||
parse_commit_header(c);
|
parse_commit_header(c);
|
||||||
|
|
||||||
switch (placeholder[0]) {
|
switch (placeholder[0]) {
|
||||||
case 's': /* subject */
|
|
||||||
strbuf_add(sb, msg + c->subject.off, c->subject.len);
|
|
||||||
return 1;
|
|
||||||
case 'a': /* author ... */
|
case 'a': /* author ... */
|
||||||
return format_person_part(sb, placeholder[1],
|
return format_person_part(sb, placeholder[1],
|
||||||
msg + c->author.off, c->author.len,
|
msg + c->author.off, c->author.len,
|
||||||
@ -614,6 +655,16 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
|
|||||||
case 'e': /* encoding */
|
case 'e': /* encoding */
|
||||||
strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
|
strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we need to parse the commit message. */
|
||||||
|
if (!c->commit_message_parsed)
|
||||||
|
parse_commit_message(c);
|
||||||
|
|
||||||
|
switch (placeholder[0]) {
|
||||||
|
case 's': /* subject */
|
||||||
|
format_subject(sb, msg + c->subject_off, " ");
|
||||||
|
return 1;
|
||||||
case 'b': /* body */
|
case 'b': /* body */
|
||||||
strbuf_addstr(sb, msg + c->body_off);
|
strbuf_addstr(sb, msg + c->body_off);
|
||||||
return 1;
|
return 1;
|
||||||
@ -704,27 +755,11 @@ void pp_title_line(enum cmit_fmt fmt,
|
|||||||
const char *encoding,
|
const char *encoding,
|
||||||
int need_8bit_cte)
|
int need_8bit_cte)
|
||||||
{
|
{
|
||||||
|
const char *line_separator = (fmt == CMIT_FMT_EMAIL) ? "\n " : " ";
|
||||||
struct strbuf title;
|
struct strbuf title;
|
||||||
|
|
||||||
strbuf_init(&title, 80);
|
strbuf_init(&title, 80);
|
||||||
|
*msg_p = format_subject(&title, *msg_p, line_separator);
|
||||||
for (;;) {
|
|
||||||
const char *line = *msg_p;
|
|
||||||
int linelen = get_one_line(line);
|
|
||||||
|
|
||||||
*msg_p += linelen;
|
|
||||||
if (!linelen || is_empty_line(line, &linelen))
|
|
||||||
break;
|
|
||||||
|
|
||||||
strbuf_grow(&title, linelen + 2);
|
|
||||||
if (title.len) {
|
|
||||||
if (fmt == CMIT_FMT_EMAIL) {
|
|
||||||
strbuf_addch(&title, '\n');
|
|
||||||
}
|
|
||||||
strbuf_addch(&title, ' ');
|
|
||||||
}
|
|
||||||
strbuf_add(&title, line, linelen);
|
|
||||||
}
|
|
||||||
|
|
||||||
strbuf_grow(sb, title.len + 1024);
|
strbuf_grow(sb, title.len + 1024);
|
||||||
if (subject) {
|
if (subject) {
|
||||||
@ -850,15 +885,7 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Skip excess blank lines at the beginning of body, if any... */
|
/* Skip excess blank lines at the beginning of body, if any... */
|
||||||
for (;;) {
|
msg = skip_empty_lines(msg);
|
||||||
int linelen = get_one_line(msg);
|
|
||||||
int ll = linelen;
|
|
||||||
if (!linelen)
|
|
||||||
break;
|
|
||||||
if (!is_empty_line(msg, &ll))
|
|
||||||
break;
|
|
||||||
msg += linelen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* These formats treat the title line specially. */
|
/* These formats treat the title line specially. */
|
||||||
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
|
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
|
||||||
|
@ -100,6 +100,12 @@ check_describe B --tags HEAD^^2^
|
|||||||
check_describe B-0-* --long HEAD^^2^
|
check_describe B-0-* --long HEAD^^2^
|
||||||
check_describe A-3-* --long HEAD^^2
|
check_describe A-3-* --long HEAD^^2
|
||||||
|
|
||||||
|
: >err.expect
|
||||||
|
check_describe A --all A^0
|
||||||
|
test_expect_success 'no warning was displayed for A' '
|
||||||
|
test_cmp err.expect err.actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'rename tag A to Q locally' '
|
test_expect_success 'rename tag A to Q locally' '
|
||||||
mv .git/refs/tags/A .git/refs/tags/Q
|
mv .git/refs/tags/A .git/refs/tags/Q
|
||||||
'
|
'
|
||||||
|
Loading…
Reference in New Issue
Block a user