Fix sparse warnings
Fix warnings from 'make check'.
- These files don't include 'builtin.h' causing sparse to complain that
cmd_* isn't declared:
builtin/clone.c:364, builtin/fetch-pack.c:797,
builtin/fmt-merge-msg.c:34, builtin/hash-object.c:78,
builtin/merge-index.c:69, builtin/merge-recursive.c:22
builtin/merge-tree.c:341, builtin/mktag.c:156, builtin/notes.c:426
builtin/notes.c:822, builtin/pack-redundant.c:596,
builtin/pack-refs.c:10, builtin/patch-id.c:60, builtin/patch-id.c:149,
builtin/remote.c:1512, builtin/remote-ext.c:240,
builtin/remote-fd.c:53, builtin/reset.c:236, builtin/send-pack.c:384,
builtin/unpack-file.c:25, builtin/var.c:75
- These files have symbols which should be marked static since they're
only file scope:
submodule.c:12, diff.c:631, replace_object.c:92, submodule.c:13,
submodule.c:14, trace.c:78, transport.c:195, transport-helper.c:79,
unpack-trees.c:19, url.c:3, url.c:18, url.c:104, url.c:117, url.c:123,
url.c:129, url.c:136, thread-utils.c:21, thread-utils.c:48
- These files redeclare symbols to be different types:
builtin/index-pack.c:210, parse-options.c:564, parse-options.c:571,
usage.c:49, usage.c:58, usage.c:63, usage.c:72
- These files use a literal integer 0 when they really should use a NULL
pointer:
daemon.c:663, fast-import.c:2942, imap-send.c:1072, notes-merge.c:362
While we're in the area, clean up some unused #includes in builtin files
(mostly exec_cmd.h).
Signed-off-by: Stephen Boyd <bebarino@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-22 07:51:05 +00:00
|
|
|
#include "builtin.h"
|
2017-06-14 18:07:36 +00:00
|
|
|
#include "config.h"
|
2023-03-21 06:25:54 +00:00
|
|
|
#include "gettext.h"
|
2008-02-29 01:45:45 +00:00
|
|
|
#include "parse-options.h"
|
2023-05-16 06:33:59 +00:00
|
|
|
#include "path.h"
|
2008-02-29 01:45:45 +00:00
|
|
|
#include "transport.h"
|
|
|
|
#include "remote.h"
|
2008-07-21 18:03:49 +00:00
|
|
|
#include "string-list.h"
|
2008-02-29 01:45:45 +00:00
|
|
|
#include "strbuf.h"
|
|
|
|
#include "run-command.h"
|
2020-01-27 07:04:27 +00:00
|
|
|
#include "rebase.h"
|
2008-02-29 01:45:45 +00:00
|
|
|
#include "refs.h"
|
2018-05-16 22:57:48 +00:00
|
|
|
#include "refspec.h"
|
2023-05-16 06:34:06 +00:00
|
|
|
#include "object-store-ll.h"
|
2020-07-28 20:23:39 +00:00
|
|
|
#include "strvec.h"
|
2018-07-20 16:33:06 +00:00
|
|
|
#include "commit-reach.h"
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
#include "progress.h"
|
2008-02-29 01:45:45 +00:00
|
|
|
|
|
|
|
static const char * const builtin_remote_usage[] = {
|
2022-01-31 22:07:48 +00:00
|
|
|
"git remote [-v | --verbose]",
|
2015-01-13 07:44:47 +00:00
|
|
|
N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--mirror=<fetch|push>] <name> <url>"),
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
N_("git remote rename [--[no-]progress] <old> <new>"),
|
2012-09-12 21:21:58 +00:00
|
|
|
N_("git remote remove <name>"),
|
2015-01-13 07:44:47 +00:00
|
|
|
N_("git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"),
|
2012-08-20 12:32:35 +00:00
|
|
|
N_("git remote [-v | --verbose] show [-n] <name>"),
|
|
|
|
N_("git remote prune [-n | --dry-run] <name>"),
|
|
|
|
N_("git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"),
|
|
|
|
N_("git remote set-branches [--add] <name> <branch>..."),
|
2015-09-16 01:53:47 +00:00
|
|
|
N_("git remote get-url [--push] [--all] <name>"),
|
2012-08-20 12:32:35 +00:00
|
|
|
N_("git remote set-url [--push] <name> <newurl> [<oldurl>]"),
|
|
|
|
N_("git remote set-url --add <name> <newurl>"),
|
|
|
|
N_("git remote set-url --delete <name> <url>"),
|
2008-02-29 01:45:45 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2009-11-20 23:43:13 +00:00
|
|
|
static const char * const builtin_remote_add_usage[] = {
|
2012-08-20 12:32:35 +00:00
|
|
|
N_("git remote add [<options>] <name> <url>"),
|
2009-11-20 23:43:13 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char * const builtin_remote_rename_usage[] = {
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
N_("git remote rename [--[no-]progress] <old> <new>"),
|
2009-11-20 23:43:13 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char * const builtin_remote_rm_usage[] = {
|
2012-09-12 21:21:58 +00:00
|
|
|
N_("git remote remove <name>"),
|
2009-11-20 23:43:13 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char * const builtin_remote_sethead_usage[] = {
|
2013-09-21 15:51:46 +00:00
|
|
|
N_("git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"),
|
2009-11-20 23:43:13 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2010-05-19 18:38:50 +00:00
|
|
|
static const char * const builtin_remote_setbranches_usage[] = {
|
2012-08-20 12:32:35 +00:00
|
|
|
N_("git remote set-branches <name> <branch>..."),
|
|
|
|
N_("git remote set-branches --add <name> <branch>..."),
|
2010-05-19 18:38:50 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2009-11-20 23:43:13 +00:00
|
|
|
static const char * const builtin_remote_show_usage[] = {
|
2012-08-20 12:32:35 +00:00
|
|
|
N_("git remote show [<options>] <name>"),
|
2009-11-20 23:43:13 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char * const builtin_remote_prune_usage[] = {
|
2012-08-20 12:32:35 +00:00
|
|
|
N_("git remote prune [<options>] <name>"),
|
2009-11-20 23:43:13 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char * const builtin_remote_update_usage[] = {
|
2012-08-20 12:32:35 +00:00
|
|
|
N_("git remote update [<options>] [<group> | <remote>]..."),
|
2009-11-20 23:43:13 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2015-09-16 01:53:47 +00:00
|
|
|
static const char * const builtin_remote_geturl_usage[] = {
|
|
|
|
N_("git remote get-url [--push] [--all] <name>"),
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2010-01-18 17:18:02 +00:00
|
|
|
static const char * const builtin_remote_seturl_usage[] = {
|
2012-08-20 12:32:35 +00:00
|
|
|
N_("git remote set-url [--push] <name> <newurl> [<oldurl>]"),
|
|
|
|
N_("git remote set-url --add <name> <newurl>"),
|
|
|
|
N_("git remote set-url --delete <name> <url>"),
|
2010-01-18 17:18:02 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2009-02-25 08:32:24 +00:00
|
|
|
#define GET_REF_STATES (1<<0)
|
|
|
|
#define GET_HEAD_NAMES (1<<1)
|
2009-02-25 08:32:28 +00:00
|
|
|
#define GET_PUSH_REF_STATES (1<<2)
|
2009-02-25 08:32:24 +00:00
|
|
|
|
2008-02-29 01:45:45 +00:00
|
|
|
static int verbose;
|
|
|
|
|
|
|
|
static int fetch_remote(const char *name)
|
|
|
|
{
|
2022-10-30 11:50:27 +00:00
|
|
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
|
|
|
|
|
|
|
strvec_push(&cmd.args, "fetch");
|
|
|
|
if (verbose)
|
|
|
|
strvec_push(&cmd.args, "-v");
|
|
|
|
strvec_push(&cmd.args, name);
|
|
|
|
cmd.git_cmd = 1;
|
2012-04-23 12:30:26 +00:00
|
|
|
printf_ln(_("Updating %s"), name);
|
2022-10-30 11:50:27 +00:00
|
|
|
if (run_command(&cmd))
|
2012-04-23 12:30:26 +00:00
|
|
|
return error(_("Could not fetch %s"), name);
|
2008-02-29 01:45:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-04-19 23:31:31 +00:00
|
|
|
enum {
|
|
|
|
TAGS_UNSET = 0,
|
|
|
|
TAGS_DEFAULT = 1,
|
|
|
|
TAGS_SET = 2
|
|
|
|
};
|
|
|
|
|
remote: separate the concept of push and fetch mirrors
git-remote currently has one option, "--mirror", which sets
up mirror configuration which can be used for either
fetching or pushing. It looks like this:
[remote "mirror"]
url = wherever
fetch = +refs/*:refs/*
mirror = true
However, a remote like this can be dangerous and confusing.
Specifically:
1. If you issue the wrong command, it can be devastating.
You are not likely to "push" when you meant to "fetch",
but "git remote update" will try to fetch it, even if
you intended the remote only for pushing. In either
case, the results can be quite destructive. An
unintended push will overwrite or delete remote refs,
and an unintended fetch can overwrite local branches.
2. The tracking setup code can produce confusing results.
The fetch refspec above means that "git checkout -b new
master" will consider refs/heads/master to come from
the remote "mirror", even if you only ever intend to
push to the mirror. It will set up the "new" branch to
track mirror's refs/heads/master.
3. The push code tries to opportunistically update
tracking branches. If you "git push mirror foo:bar",
it will see that we are updating mirror's
refs/heads/bar, which corresponds to our local
refs/heads/bar, and will update our local branch.
To solve this, we split the concept into "push mirrors" and
"fetch mirrors". Push mirrors set only remote.*.mirror,
solving (2) and (3), and making an accidental fetch write
only into FETCH_HEAD. Fetch mirrors set only the fetch
refspec, meaning an accidental push will not force-overwrite
or delete refs on the remote end.
The new syntax is "--mirror=<fetch|push>". For
compatibility, we keep "--mirror" as-is, setting up both
types simultaneously.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-30 19:53:19 +00:00
|
|
|
#define MIRROR_NONE 0
|
|
|
|
#define MIRROR_FETCH 1
|
|
|
|
#define MIRROR_PUSH 2
|
|
|
|
#define MIRROR_BOTH (MIRROR_FETCH|MIRROR_PUSH)
|
|
|
|
|
2016-02-22 11:23:29 +00:00
|
|
|
static void add_branch(const char *key, const char *branchname,
|
|
|
|
const char *remotename, int mirror, struct strbuf *tmp)
|
2010-05-19 18:38:50 +00:00
|
|
|
{
|
|
|
|
strbuf_reset(tmp);
|
|
|
|
strbuf_addch(tmp, '+');
|
|
|
|
if (mirror)
|
|
|
|
strbuf_addf(tmp, "refs/%s:refs/%s",
|
|
|
|
branchname, branchname);
|
|
|
|
else
|
|
|
|
strbuf_addf(tmp, "refs/heads/%s:refs/remotes/%s/%s",
|
|
|
|
branchname, remotename, branchname);
|
2016-02-22 11:23:36 +00:00
|
|
|
git_config_set_multivar(key, tmp->buf, "^$", 0);
|
2010-05-19 18:38:50 +00:00
|
|
|
}
|
|
|
|
|
2011-03-30 19:53:39 +00:00
|
|
|
static const char mirror_advice[] =
|
2012-04-23 12:30:26 +00:00
|
|
|
N_("--mirror is dangerous and deprecated; please\n"
|
|
|
|
"\t use --mirror=fetch or --mirror=push instead");
|
2011-03-30 19:53:39 +00:00
|
|
|
|
remote: separate the concept of push and fetch mirrors
git-remote currently has one option, "--mirror", which sets
up mirror configuration which can be used for either
fetching or pushing. It looks like this:
[remote "mirror"]
url = wherever
fetch = +refs/*:refs/*
mirror = true
However, a remote like this can be dangerous and confusing.
Specifically:
1. If you issue the wrong command, it can be devastating.
You are not likely to "push" when you meant to "fetch",
but "git remote update" will try to fetch it, even if
you intended the remote only for pushing. In either
case, the results can be quite destructive. An
unintended push will overwrite or delete remote refs,
and an unintended fetch can overwrite local branches.
2. The tracking setup code can produce confusing results.
The fetch refspec above means that "git checkout -b new
master" will consider refs/heads/master to come from
the remote "mirror", even if you only ever intend to
push to the mirror. It will set up the "new" branch to
track mirror's refs/heads/master.
3. The push code tries to opportunistically update
tracking branches. If you "git push mirror foo:bar",
it will see that we are updating mirror's
refs/heads/bar, which corresponds to our local
refs/heads/bar, and will update our local branch.
To solve this, we split the concept into "push mirrors" and
"fetch mirrors". Push mirrors set only remote.*.mirror,
solving (2) and (3), and making an accidental fetch write
only into FETCH_HEAD. Fetch mirrors set only the fetch
refspec, meaning an accidental push will not force-overwrite
or delete refs on the remote end.
The new syntax is "--mirror=<fetch|push>". For
compatibility, we keep "--mirror" as-is, setting up both
types simultaneously.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-30 19:53:19 +00:00
|
|
|
static int parse_mirror_opt(const struct option *opt, const char *arg, int not)
|
|
|
|
{
|
|
|
|
unsigned *mirror = opt->value;
|
|
|
|
if (not)
|
|
|
|
*mirror = MIRROR_NONE;
|
2011-03-30 19:53:39 +00:00
|
|
|
else if (!arg) {
|
2012-04-23 12:30:26 +00:00
|
|
|
warning("%s", _(mirror_advice));
|
remote: separate the concept of push and fetch mirrors
git-remote currently has one option, "--mirror", which sets
up mirror configuration which can be used for either
fetching or pushing. It looks like this:
[remote "mirror"]
url = wherever
fetch = +refs/*:refs/*
mirror = true
However, a remote like this can be dangerous and confusing.
Specifically:
1. If you issue the wrong command, it can be devastating.
You are not likely to "push" when you meant to "fetch",
but "git remote update" will try to fetch it, even if
you intended the remote only for pushing. In either
case, the results can be quite destructive. An
unintended push will overwrite or delete remote refs,
and an unintended fetch can overwrite local branches.
2. The tracking setup code can produce confusing results.
The fetch refspec above means that "git checkout -b new
master" will consider refs/heads/master to come from
the remote "mirror", even if you only ever intend to
push to the mirror. It will set up the "new" branch to
track mirror's refs/heads/master.
3. The push code tries to opportunistically update
tracking branches. If you "git push mirror foo:bar",
it will see that we are updating mirror's
refs/heads/bar, which corresponds to our local
refs/heads/bar, and will update our local branch.
To solve this, we split the concept into "push mirrors" and
"fetch mirrors". Push mirrors set only remote.*.mirror,
solving (2) and (3), and making an accidental fetch write
only into FETCH_HEAD. Fetch mirrors set only the fetch
refspec, meaning an accidental push will not force-overwrite
or delete refs on the remote end.
The new syntax is "--mirror=<fetch|push>". For
compatibility, we keep "--mirror" as-is, setting up both
types simultaneously.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-30 19:53:19 +00:00
|
|
|
*mirror = MIRROR_BOTH;
|
2011-03-30 19:53:39 +00:00
|
|
|
}
|
remote: separate the concept of push and fetch mirrors
git-remote currently has one option, "--mirror", which sets
up mirror configuration which can be used for either
fetching or pushing. It looks like this:
[remote "mirror"]
url = wherever
fetch = +refs/*:refs/*
mirror = true
However, a remote like this can be dangerous and confusing.
Specifically:
1. If you issue the wrong command, it can be devastating.
You are not likely to "push" when you meant to "fetch",
but "git remote update" will try to fetch it, even if
you intended the remote only for pushing. In either
case, the results can be quite destructive. An
unintended push will overwrite or delete remote refs,
and an unintended fetch can overwrite local branches.
2. The tracking setup code can produce confusing results.
The fetch refspec above means that "git checkout -b new
master" will consider refs/heads/master to come from
the remote "mirror", even if you only ever intend to
push to the mirror. It will set up the "new" branch to
track mirror's refs/heads/master.
3. The push code tries to opportunistically update
tracking branches. If you "git push mirror foo:bar",
it will see that we are updating mirror's
refs/heads/bar, which corresponds to our local
refs/heads/bar, and will update our local branch.
To solve this, we split the concept into "push mirrors" and
"fetch mirrors". Push mirrors set only remote.*.mirror,
solving (2) and (3), and making an accidental fetch write
only into FETCH_HEAD. Fetch mirrors set only the fetch
refspec, meaning an accidental push will not force-overwrite
or delete refs on the remote end.
The new syntax is "--mirror=<fetch|push>". For
compatibility, we keep "--mirror" as-is, setting up both
types simultaneously.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-30 19:53:19 +00:00
|
|
|
else if (!strcmp(arg, "fetch"))
|
|
|
|
*mirror = MIRROR_FETCH;
|
|
|
|
else if (!strcmp(arg, "push"))
|
|
|
|
*mirror = MIRROR_PUSH;
|
|
|
|
else
|
2024-02-16 10:15:35 +00:00
|
|
|
return error(_("unknown --mirror argument: %s"), arg);
|
remote: separate the concept of push and fetch mirrors
git-remote currently has one option, "--mirror", which sets
up mirror configuration which can be used for either
fetching or pushing. It looks like this:
[remote "mirror"]
url = wherever
fetch = +refs/*:refs/*
mirror = true
However, a remote like this can be dangerous and confusing.
Specifically:
1. If you issue the wrong command, it can be devastating.
You are not likely to "push" when you meant to "fetch",
but "git remote update" will try to fetch it, even if
you intended the remote only for pushing. In either
case, the results can be quite destructive. An
unintended push will overwrite or delete remote refs,
and an unintended fetch can overwrite local branches.
2. The tracking setup code can produce confusing results.
The fetch refspec above means that "git checkout -b new
master" will consider refs/heads/master to come from
the remote "mirror", even if you only ever intend to
push to the mirror. It will set up the "new" branch to
track mirror's refs/heads/master.
3. The push code tries to opportunistically update
tracking branches. If you "git push mirror foo:bar",
it will see that we are updating mirror's
refs/heads/bar, which corresponds to our local
refs/heads/bar, and will update our local branch.
To solve this, we split the concept into "push mirrors" and
"fetch mirrors". Push mirrors set only remote.*.mirror,
solving (2) and (3), and making an accidental fetch write
only into FETCH_HEAD. Fetch mirrors set only the fetch
refspec, meaning an accidental push will not force-overwrite
or delete refs on the remote end.
The new syntax is "--mirror=<fetch|push>". For
compatibility, we keep "--mirror" as-is, setting up both
types simultaneously.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-30 19:53:19 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-19 16:04:08 +00:00
|
|
|
static int add(int argc, const char **argv, const char *prefix)
|
2008-02-29 01:45:45 +00:00
|
|
|
{
|
remote: separate the concept of push and fetch mirrors
git-remote currently has one option, "--mirror", which sets
up mirror configuration which can be used for either
fetching or pushing. It looks like this:
[remote "mirror"]
url = wherever
fetch = +refs/*:refs/*
mirror = true
However, a remote like this can be dangerous and confusing.
Specifically:
1. If you issue the wrong command, it can be devastating.
You are not likely to "push" when you meant to "fetch",
but "git remote update" will try to fetch it, even if
you intended the remote only for pushing. In either
case, the results can be quite destructive. An
unintended push will overwrite or delete remote refs,
and an unintended fetch can overwrite local branches.
2. The tracking setup code can produce confusing results.
The fetch refspec above means that "git checkout -b new
master" will consider refs/heads/master to come from
the remote "mirror", even if you only ever intend to
push to the mirror. It will set up the "new" branch to
track mirror's refs/heads/master.
3. The push code tries to opportunistically update
tracking branches. If you "git push mirror foo:bar",
it will see that we are updating mirror's
refs/heads/bar, which corresponds to our local
refs/heads/bar, and will update our local branch.
To solve this, we split the concept into "push mirrors" and
"fetch mirrors". Push mirrors set only remote.*.mirror,
solving (2) and (3), and making an accidental fetch write
only into FETCH_HEAD. Fetch mirrors set only the fetch
refspec, meaning an accidental push will not force-overwrite
or delete refs on the remote end.
The new syntax is "--mirror=<fetch|push>". For
compatibility, we keep "--mirror" as-is, setting up both
types simultaneously.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-30 19:53:19 +00:00
|
|
|
int fetch = 0, fetch_tags = TAGS_DEFAULT;
|
|
|
|
unsigned mirror = MIRROR_NONE;
|
2010-07-04 19:46:19 +00:00
|
|
|
struct string_list track = STRING_LIST_INIT_NODUP;
|
2008-02-29 01:45:45 +00:00
|
|
|
const char *master = NULL;
|
|
|
|
struct remote *remote;
|
2008-10-09 19:12:12 +00:00
|
|
|
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
|
2008-02-29 01:45:45 +00:00
|
|
|
const char *name, *url;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
struct option options[] = {
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL('f', "fetch", &fetch, N_("fetch the remote branches")),
|
2010-04-19 23:31:31 +00:00
|
|
|
OPT_SET_INT(0, "tags", &fetch_tags,
|
2023-07-18 22:31:03 +00:00
|
|
|
N_("import all tags and associated objects when fetching\n"
|
|
|
|
"or do not fetch any tag at all (--no-tags)"),
|
2010-04-19 23:31:31 +00:00
|
|
|
TAGS_SET),
|
2012-08-20 12:32:35 +00:00
|
|
|
OPT_STRING_LIST('t', "track", &track, N_("branch"),
|
|
|
|
N_("branch(es) to track")),
|
|
|
|
OPT_STRING('m', "master", &master, N_("branch"), N_("master branch")),
|
Use OPT_CALLBACK and OPT_CALLBACK_F
In the codebase, there are many options which use OPTION_CALLBACK in a
plain ol' struct definition. However, we have the OPT_CALLBACK and
OPT_CALLBACK_F macros which are meant to abstract these plain struct
definitions away. These macros are useful as they semantically signal to
developers that these are just normal callback option with nothing fancy
happening.
Replace plain struct definitions of OPTION_CALLBACK with OPT_CALLBACK or
OPT_CALLBACK_F where applicable. The heavy lifting was done using the
following (disgusting) shell script:
#!/bin/sh
do_replacement () {
tr '\n' '\r' |
sed -e 's/{\s*OPTION_CALLBACK,\s*\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\s*0,\(\s*[^[:space:]}]*\)\s*}/OPT_CALLBACK(\1,\2,\3,\4,\5,\6)/g' |
sed -e 's/{\s*OPTION_CALLBACK,\s*\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\(\s*[^[:space:]}]*\)\s*}/OPT_CALLBACK_F(\1,\2,\3,\4,\5,\6,\7)/g' |
tr '\r' '\n'
}
for f in $(git ls-files \*.c)
do
do_replacement <"$f" >"$f.tmp"
mv "$f.tmp" "$f"
done
The result was manually inspected and then reformatted to match the
style of the surrounding code. Finally, using
`git grep OPTION_CALLBACK \*.c`, leftover results which were not handled
by the script were manually transformed.
Signed-off-by: Denton Liu <liu.denton@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-28 08:36:28 +00:00
|
|
|
OPT_CALLBACK_F(0, "mirror", &mirror, "(push|fetch)",
|
2012-08-20 12:32:35 +00:00
|
|
|
N_("set up remote as a mirror to push to or fetch from"),
|
Use OPT_CALLBACK and OPT_CALLBACK_F
In the codebase, there are many options which use OPTION_CALLBACK in a
plain ol' struct definition. However, we have the OPT_CALLBACK and
OPT_CALLBACK_F macros which are meant to abstract these plain struct
definitions away. These macros are useful as they semantically signal to
developers that these are just normal callback option with nothing fancy
happening.
Replace plain struct definitions of OPTION_CALLBACK with OPT_CALLBACK or
OPT_CALLBACK_F where applicable. The heavy lifting was done using the
following (disgusting) shell script:
#!/bin/sh
do_replacement () {
tr '\n' '\r' |
sed -e 's/{\s*OPTION_CALLBACK,\s*\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\s*0,\(\s*[^[:space:]}]*\)\s*}/OPT_CALLBACK(\1,\2,\3,\4,\5,\6)/g' |
sed -e 's/{\s*OPTION_CALLBACK,\s*\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\(\s*[^[:space:]}]*\)\s*}/OPT_CALLBACK_F(\1,\2,\3,\4,\5,\6,\7)/g' |
tr '\r' '\n'
}
for f in $(git ls-files \*.c)
do
do_replacement <"$f" >"$f.tmp"
mv "$f.tmp" "$f"
done
The result was manually inspected and then reformatted to match the
style of the surrounding code. Finally, using
`git grep OPTION_CALLBACK \*.c`, leftover results which were not handled
by the script were manually transformed.
Signed-off-by: Denton Liu <liu.denton@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-28 08:36:28 +00:00
|
|
|
PARSE_OPT_OPTARG | PARSE_OPT_COMP_ARG, parse_mirror_opt),
|
2008-02-29 01:45:45 +00:00
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
pass subcommand "prefix" arguments to parse_options()
Recent commits such as bf0a6b65fc (builtin/multi-pack-index.c: let
parse-options parse subcommands, 2022-08-19) converted a few functions
to match our usual argc/argv/prefix conventions, but the prefix argument
remains unused.
However, there is a good use for it: they should pass it to their own
parse_options() functions, where it may be used to adjust the value of
any filename options. In all but one of these functions, there's no
behavior change, since they don't use OPT_FILENAME. But this is an
actual fix for one option, which you can see by modifying the test suite
like so:
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 4fe57414c1..d0974d4371 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -186,7 +186,11 @@ test_expect_success 'writing a bitmap with --refs-snapshot' '
# Then again, but with a refs snapshot which only sees
# refs/tags/one.
- git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
+ (
+ mkdir subdir &&
+ cd subdir &&
+ git multi-pack-index write --bitmap --refs-snapshot=../snapshot
+ ) &&
test_path_is_file $midx &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
I'd emphasize that this wasn't broken by bf0a6b65fc; it has been broken
all along, because the sub-function never got to see the prefix. It is
that commit which is actually enabling us to fix it (and which also
brought attention to the problem because it triggers -Wunused-parameter!)
The other functions changed here don't use OPT_FILENAME at all. In their
cases this isn't fixing anything visible, but it's following the usual
pattern and future-proofing them against somebody adding new options and
being surprised.
I didn't include a test for the one visible case above. We don't
generally test routine parse-options behavior for individual options.
The challenge here was finding the problem, and now that this has been
done, it's not likely to regress. Likewise, we could apply the patch
above to cover it "for free" but it makes reading the rest of the test
unnecessarily complicated.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-08-25 10:47:00 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, options,
|
|
|
|
builtin_remote_add_usage, 0);
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2013-04-24 13:54:36 +00:00
|
|
|
if (argc != 2)
|
2009-11-20 23:43:13 +00:00
|
|
|
usage_with_options(builtin_remote_add_usage, options);
|
2008-02-29 01:45:45 +00:00
|
|
|
|
remote: disallow some nonsensical option combinations
It doesn't make sense to use "-m" on a mirror, since "-m"
sets up the HEAD symref in the remotes namespace, but with
mirror, we are by definition not using a remotes namespace.
Similarly, it does not make much sense to specify refspecs
with --mirror. For a mirror you plan to push to, those
refspecs will be ignored. For a mirror you are fetching
from, there is no point in mirroring, since the refspec
specifies everything you want to grab.
There is one case where "--mirror -t <X>" would be useful.
Because <X> is used as-is in the refspec, and because we
append it to to refs/, you could mirror a subset of the
hierarchy by doing:
git remote add --mirror -t 'tags/*'
But using anything besides a single branch as an argument to
"-t" is not documented and only happens to work, so closing
it off is not a serious regression.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-30 19:52:52 +00:00
|
|
|
if (mirror && master)
|
2012-04-23 12:30:26 +00:00
|
|
|
die(_("specifying a master branch makes no sense with --mirror"));
|
2011-05-26 15:11:00 +00:00
|
|
|
if (mirror && !(mirror & MIRROR_FETCH) && track.nr)
|
2012-04-23 12:30:26 +00:00
|
|
|
die(_("specifying branches to track makes sense only with fetch mirrors"));
|
remote: disallow some nonsensical option combinations
It doesn't make sense to use "-m" on a mirror, since "-m"
sets up the HEAD symref in the remotes namespace, but with
mirror, we are by definition not using a remotes namespace.
Similarly, it does not make much sense to specify refspecs
with --mirror. For a mirror you plan to push to, those
refspecs will be ignored. For a mirror you are fetching
from, there is no point in mirroring, since the refspec
specifies everything you want to grab.
There is one case where "--mirror -t <X>" would be useful.
Because <X> is used as-is in the refspec, and because we
append it to to refs/, you could mirror a subset of the
hierarchy by doing:
git remote add --mirror -t 'tags/*'
But using anything besides a single branch as an argument to
"-t" is not documented and only happens to work, so closing
it off is not a serious regression.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-30 19:52:52 +00:00
|
|
|
|
2008-02-29 01:45:45 +00:00
|
|
|
name = argv[0];
|
|
|
|
url = argv[1];
|
|
|
|
|
|
|
|
remote = remote_get(name);
|
2020-10-27 09:41:36 +00:00
|
|
|
if (remote_is_configured(remote, 1)) {
|
|
|
|
error(_("remote %s already exists."), name);
|
|
|
|
exit(3);
|
|
|
|
}
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2020-10-01 03:46:13 +00:00
|
|
|
if (!valid_remote_name(name))
|
2012-04-23 12:30:26 +00:00
|
|
|
die(_("'%s' is not a valid remote name"), name);
|
2008-04-13 09:56:54 +00:00
|
|
|
|
2008-02-29 01:45:45 +00:00
|
|
|
strbuf_addf(&buf, "remote.%s.url", name);
|
2016-02-22 11:23:36 +00:00
|
|
|
git_config_set(buf.buf, url);
|
2008-02-29 01:45:45 +00:00
|
|
|
|
remote: separate the concept of push and fetch mirrors
git-remote currently has one option, "--mirror", which sets
up mirror configuration which can be used for either
fetching or pushing. It looks like this:
[remote "mirror"]
url = wherever
fetch = +refs/*:refs/*
mirror = true
However, a remote like this can be dangerous and confusing.
Specifically:
1. If you issue the wrong command, it can be devastating.
You are not likely to "push" when you meant to "fetch",
but "git remote update" will try to fetch it, even if
you intended the remote only for pushing. In either
case, the results can be quite destructive. An
unintended push will overwrite or delete remote refs,
and an unintended fetch can overwrite local branches.
2. The tracking setup code can produce confusing results.
The fetch refspec above means that "git checkout -b new
master" will consider refs/heads/master to come from
the remote "mirror", even if you only ever intend to
push to the mirror. It will set up the "new" branch to
track mirror's refs/heads/master.
3. The push code tries to opportunistically update
tracking branches. If you "git push mirror foo:bar",
it will see that we are updating mirror's
refs/heads/bar, which corresponds to our local
refs/heads/bar, and will update our local branch.
To solve this, we split the concept into "push mirrors" and
"fetch mirrors". Push mirrors set only remote.*.mirror,
solving (2) and (3), and making an accidental fetch write
only into FETCH_HEAD. Fetch mirrors set only the fetch
refspec, meaning an accidental push will not force-overwrite
or delete refs on the remote end.
The new syntax is "--mirror=<fetch|push>". For
compatibility, we keep "--mirror" as-is, setting up both
types simultaneously.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-30 19:53:19 +00:00
|
|
|
if (!mirror || mirror & MIRROR_FETCH) {
|
|
|
|
strbuf_reset(&buf);
|
|
|
|
strbuf_addf(&buf, "remote.%s.fetch", name);
|
|
|
|
if (track.nr == 0)
|
|
|
|
string_list_append(&track, "*");
|
|
|
|
for (i = 0; i < track.nr; i++) {
|
2016-02-22 11:23:29 +00:00
|
|
|
add_branch(buf.buf, track.items[i].string,
|
|
|
|
name, mirror, &buf2);
|
remote: separate the concept of push and fetch mirrors
git-remote currently has one option, "--mirror", which sets
up mirror configuration which can be used for either
fetching or pushing. It looks like this:
[remote "mirror"]
url = wherever
fetch = +refs/*:refs/*
mirror = true
However, a remote like this can be dangerous and confusing.
Specifically:
1. If you issue the wrong command, it can be devastating.
You are not likely to "push" when you meant to "fetch",
but "git remote update" will try to fetch it, even if
you intended the remote only for pushing. In either
case, the results can be quite destructive. An
unintended push will overwrite or delete remote refs,
and an unintended fetch can overwrite local branches.
2. The tracking setup code can produce confusing results.
The fetch refspec above means that "git checkout -b new
master" will consider refs/heads/master to come from
the remote "mirror", even if you only ever intend to
push to the mirror. It will set up the "new" branch to
track mirror's refs/heads/master.
3. The push code tries to opportunistically update
tracking branches. If you "git push mirror foo:bar",
it will see that we are updating mirror's
refs/heads/bar, which corresponds to our local
refs/heads/bar, and will update our local branch.
To solve this, we split the concept into "push mirrors" and
"fetch mirrors". Push mirrors set only remote.*.mirror,
solving (2) and (3), and making an accidental fetch write
only into FETCH_HEAD. Fetch mirrors set only the fetch
refspec, meaning an accidental push will not force-overwrite
or delete refs on the remote end.
The new syntax is "--mirror=<fetch|push>". For
compatibility, we keep "--mirror" as-is, setting up both
types simultaneously.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-30 19:53:19 +00:00
|
|
|
}
|
2008-02-29 01:45:45 +00:00
|
|
|
}
|
|
|
|
|
remote: separate the concept of push and fetch mirrors
git-remote currently has one option, "--mirror", which sets
up mirror configuration which can be used for either
fetching or pushing. It looks like this:
[remote "mirror"]
url = wherever
fetch = +refs/*:refs/*
mirror = true
However, a remote like this can be dangerous and confusing.
Specifically:
1. If you issue the wrong command, it can be devastating.
You are not likely to "push" when you meant to "fetch",
but "git remote update" will try to fetch it, even if
you intended the remote only for pushing. In either
case, the results can be quite destructive. An
unintended push will overwrite or delete remote refs,
and an unintended fetch can overwrite local branches.
2. The tracking setup code can produce confusing results.
The fetch refspec above means that "git checkout -b new
master" will consider refs/heads/master to come from
the remote "mirror", even if you only ever intend to
push to the mirror. It will set up the "new" branch to
track mirror's refs/heads/master.
3. The push code tries to opportunistically update
tracking branches. If you "git push mirror foo:bar",
it will see that we are updating mirror's
refs/heads/bar, which corresponds to our local
refs/heads/bar, and will update our local branch.
To solve this, we split the concept into "push mirrors" and
"fetch mirrors". Push mirrors set only remote.*.mirror,
solving (2) and (3), and making an accidental fetch write
only into FETCH_HEAD. Fetch mirrors set only the fetch
refspec, meaning an accidental push will not force-overwrite
or delete refs on the remote end.
The new syntax is "--mirror=<fetch|push>". For
compatibility, we keep "--mirror" as-is, setting up both
types simultaneously.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-30 19:53:19 +00:00
|
|
|
if (mirror & MIRROR_PUSH) {
|
2008-04-17 11:17:20 +00:00
|
|
|
strbuf_reset(&buf);
|
|
|
|
strbuf_addf(&buf, "remote.%s.mirror", name);
|
2016-02-22 11:23:36 +00:00
|
|
|
git_config_set(buf.buf, "true");
|
2008-04-17 11:17:20 +00:00
|
|
|
}
|
|
|
|
|
2010-04-19 23:31:31 +00:00
|
|
|
if (fetch_tags != TAGS_DEFAULT) {
|
|
|
|
strbuf_reset(&buf);
|
2021-02-25 01:21:16 +00:00
|
|
|
strbuf_addf(&buf, "remote.%s.tagOpt", name);
|
2016-02-22 11:23:36 +00:00
|
|
|
git_config_set(buf.buf,
|
|
|
|
fetch_tags == TAGS_SET ? "--tags" : "--no-tags");
|
2010-04-19 23:31:31 +00:00
|
|
|
}
|
|
|
|
|
2008-02-29 01:45:45 +00:00
|
|
|
if (fetch && fetch_remote(name))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (master) {
|
|
|
|
strbuf_reset(&buf);
|
|
|
|
strbuf_addf(&buf, "refs/remotes/%s/HEAD", name);
|
|
|
|
|
|
|
|
strbuf_reset(&buf2);
|
|
|
|
strbuf_addf(&buf2, "refs/remotes/%s/%s", name, master);
|
|
|
|
|
2024-05-20 18:20:04 +00:00
|
|
|
if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote add"))
|
2012-04-23 12:30:26 +00:00
|
|
|
return error(_("Could not setup master '%s'"), master);
|
2008-02-29 01:45:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
strbuf_release(&buf);
|
|
|
|
strbuf_release(&buf2);
|
2008-07-21 18:03:49 +00:00
|
|
|
string_list_clear(&track, 0);
|
2008-02-29 01:45:45 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct branch_info {
|
2009-02-25 08:32:21 +00:00
|
|
|
char *remote_name;
|
2008-07-21 18:03:49 +00:00
|
|
|
struct string_list merge;
|
2020-01-27 07:04:27 +00:00
|
|
|
enum rebase_type rebase;
|
2020-01-27 07:04:30 +00:00
|
|
|
char *push_remote_name;
|
2008-02-29 01:45:45 +00:00
|
|
|
};
|
|
|
|
|
2024-08-01 10:40:07 +00:00
|
|
|
static struct string_list branch_list = STRING_LIST_INIT_DUP;
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2008-07-18 04:30:33 +00:00
|
|
|
static const char *abbrev_ref(const char *name, const char *prefix)
|
|
|
|
{
|
refactor skip_prefix to return a boolean
The skip_prefix() function returns a pointer to the content
past the prefix, or NULL if the prefix was not found. While
this is nice and simple, in practice it makes it hard to use
for two reasons:
1. When you want to conditionally skip or keep the string
as-is, you have to introduce a temporary variable.
For example:
tmp = skip_prefix(buf, "foo");
if (tmp)
buf = tmp;
2. It is verbose to check the outcome in a conditional, as
you need extra parentheses to silence compiler
warnings. For example:
if ((cp = skip_prefix(buf, "foo"))
/* do something with cp */
Both of these make it harder to use for long if-chains, and
we tend to use starts_with() instead. However, the first line
of "do something" is often to then skip forward in buf past
the prefix, either using a magic constant or with an extra
strlen(3) (which is generally computed at compile time, but
means we are repeating ourselves).
This patch refactors skip_prefix() to return a simple boolean,
and to provide the pointer value as an out-parameter. If the
prefix is not found, the out-parameter is untouched. This
lets you write:
if (skip_prefix(arg, "foo ", &arg))
do_foo(arg);
else if (skip_prefix(arg, "bar ", &arg))
do_bar(arg);
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-06-18 19:44:19 +00:00
|
|
|
skip_prefix(name, prefix, &name);
|
2008-07-18 04:30:33 +00:00
|
|
|
return name;
|
|
|
|
}
|
|
|
|
#define abbrev_branch(name) abbrev_ref((name), "refs/heads/")
|
|
|
|
|
2022-08-19 10:08:32 +00:00
|
|
|
static int config_read_branches(const char *key, const char *value,
|
config: add ctx arg to config_fn_t
Add a new "const struct config_context *ctx" arg to config_fn_t to hold
additional information about the config iteration operation.
config_context has a "struct key_value_info kvi" member that holds
metadata about the config source being read (e.g. what kind of config
source it is, the filename, etc). In this series, we're only interested
in .kvi, so we could have just used "struct key_value_info" as an arg,
but config_context makes it possible to add/adjust members in the future
without changing the config_fn_t signature. We could also consider other
ways of organizing the args (e.g. moving the config name and value into
config_context or key_value_info), but in my experiments, the
incremental benefit doesn't justify the added complexity (e.g. a
config_fn_t will sometimes invoke another config_fn_t but with a
different config value).
In subsequent commits, the .kvi member will replace the global "struct
config_reader" in config.c, making config iteration a global-free
operation. It requires much more work for the machinery to provide
meaningful values of .kvi, so for now, merely change the signature and
call sites, pass NULL as a placeholder value, and don't rely on the arg
in any meaningful way.
Most of the changes are performed by
contrib/coccinelle/config_fn_ctx.pending.cocci, which, for every
config_fn_t:
- Modifies the signature to accept "const struct config_context *ctx"
- Passes "ctx" to any inner config_fn_t, if needed
- Adds UNUSED attributes to "ctx", if needed
Most config_fn_t instances are easily identified by seeing if they are
called by the various config functions. Most of the remaining ones are
manually named in the .cocci patch. Manual cleanups are still needed,
but the majority of it is trivial; it's either adjusting config_fn_t
that the .cocci patch didn't catch, or adding forward declarations of
"struct config_context ctx" to make the signatures make sense.
The non-trivial changes are in cases where we are invoking a config_fn_t
outside of config machinery, and we now need to decide what value of
"ctx" to pass. These cases are:
- trace2/tr2_cfg.c:tr2_cfg_set_fl()
This is indirectly called by git_config_set() so that the trace2
machinery can notice the new config values and update its settings
using the tr2 config parsing function, i.e. tr2_cfg_cb().
- builtin/checkout.c:checkout_main()
This calls git_xmerge_config() as a shorthand for parsing a CLI arg.
This might be worth refactoring away in the future, since
git_xmerge_config() can call git_default_config(), which can do much
more than just parsing.
Handle them by creating a KVI_INIT macro that initializes "struct
key_value_info" to a reasonable default, and use that to construct the
"ctx" arg.
Signed-off-by: Glen Choo <chooglen@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-06-28 19:26:22 +00:00
|
|
|
const struct config_context *ctx UNUSED,
|
2022-08-25 17:09:48 +00:00
|
|
|
void *data UNUSED)
|
2008-02-29 01:45:45 +00:00
|
|
|
{
|
2020-01-27 07:04:28 +00:00
|
|
|
const char *orig_key = key;
|
|
|
|
char *name;
|
|
|
|
struct string_list_item *item;
|
|
|
|
struct branch_info *info;
|
2020-01-27 07:04:30 +00:00
|
|
|
enum { REMOTE, MERGE, REBASE, PUSH_REMOTE } type;
|
2020-01-27 07:04:28 +00:00
|
|
|
size_t key_len;
|
|
|
|
|
|
|
|
if (!starts_with(key, "branch."))
|
|
|
|
return 0;
|
|
|
|
|
2020-01-27 07:04:29 +00:00
|
|
|
key += strlen("branch.");
|
|
|
|
if (strip_suffix(key, ".remote", &key_len))
|
2020-01-27 07:04:28 +00:00
|
|
|
type = REMOTE;
|
2020-01-27 07:04:29 +00:00
|
|
|
else if (strip_suffix(key, ".merge", &key_len))
|
2020-01-27 07:04:28 +00:00
|
|
|
type = MERGE;
|
2020-01-27 07:04:29 +00:00
|
|
|
else if (strip_suffix(key, ".rebase", &key_len))
|
2020-01-27 07:04:28 +00:00
|
|
|
type = REBASE;
|
2020-01-27 07:04:30 +00:00
|
|
|
else if (strip_suffix(key, ".pushremote", &key_len))
|
|
|
|
type = PUSH_REMOTE;
|
2020-01-27 07:04:29 +00:00
|
|
|
else
|
2020-01-27 07:04:28 +00:00
|
|
|
return 0;
|
|
|
|
|
2024-08-01 10:40:07 +00:00
|
|
|
name = xmemdupz(key, key_len);
|
2020-01-27 07:04:28 +00:00
|
|
|
item = string_list_insert(&branch_list, name);
|
|
|
|
|
|
|
|
if (!item->util)
|
|
|
|
item->util = xcalloc(1, sizeof(struct branch_info));
|
|
|
|
info = item->util;
|
2020-01-27 07:04:29 +00:00
|
|
|
switch (type) {
|
|
|
|
case REMOTE:
|
2020-01-27 07:04:28 +00:00
|
|
|
if (info->remote_name)
|
|
|
|
warning(_("more than one %s"), orig_key);
|
|
|
|
info->remote_name = xstrdup(value);
|
2020-01-27 07:04:29 +00:00
|
|
|
break;
|
|
|
|
case MERGE: {
|
2020-01-27 07:04:28 +00:00
|
|
|
char *space = strchr(value, ' ');
|
|
|
|
value = abbrev_branch(value);
|
|
|
|
while (space) {
|
|
|
|
char *merge;
|
|
|
|
merge = xstrndup(value, space - value);
|
|
|
|
string_list_append(&info->merge, merge);
|
|
|
|
value = abbrev_branch(space + 1);
|
|
|
|
space = strchr(value, ' ');
|
|
|
|
}
|
|
|
|
string_list_append(&info->merge, xstrdup(value));
|
2020-01-27 07:04:29 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case REBASE:
|
2020-01-27 07:04:28 +00:00
|
|
|
/*
|
|
|
|
* Consider invalid values as false and check the
|
|
|
|
* truth value with >= REBASE_TRUE.
|
|
|
|
*/
|
|
|
|
info->rebase = rebase_parse_value(value);
|
2021-09-07 21:05:03 +00:00
|
|
|
if (info->rebase == REBASE_INVALID)
|
|
|
|
warning(_("unhandled branch.%s.rebase=%s; assuming "
|
|
|
|
"'true'"), name, value);
|
2020-01-27 07:04:29 +00:00
|
|
|
break;
|
2020-01-27 07:04:30 +00:00
|
|
|
case PUSH_REMOTE:
|
|
|
|
if (info->push_remote_name)
|
|
|
|
warning(_("more than one %s"), orig_key);
|
|
|
|
info->push_remote_name = xstrdup(value);
|
|
|
|
break;
|
2020-01-27 07:04:29 +00:00
|
|
|
default:
|
|
|
|
BUG("unexpected type=%d", type);
|
|
|
|
}
|
2020-01-27 07:04:28 +00:00
|
|
|
|
2024-08-01 10:40:07 +00:00
|
|
|
free(name);
|
2008-02-29 01:45:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void read_branches(void)
|
|
|
|
{
|
|
|
|
if (branch_list.nr)
|
|
|
|
return;
|
2008-05-14 17:46:53 +00:00
|
|
|
git_config(config_read_branches, NULL);
|
2008-02-29 01:45:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct ref_states {
|
|
|
|
struct remote *remote;
|
2022-06-17 00:20:31 +00:00
|
|
|
struct string_list new_refs, skipped, stale, tracked, heads, push;
|
2009-02-25 08:32:27 +00:00
|
|
|
int queried;
|
2008-02-29 01:45:45 +00:00
|
|
|
};
|
|
|
|
|
builtin/remote.c: add and use a REF_STATES_INIT
Use a new REF_STATES_INIT designated initializer instead of assigning
to the "strdup_strings" member of the previously memzero()'d version
of this struct.
The pattern of assigning to "strdup_strings" dates back to
211c89682ee (Make git-remote a builtin, 2008-02-29) (when it was
"strdup_paths"), i.e. long before we used anything like our current
established *_INIT patterns consistently.
Then in e61e0cc6b70 (builtin-remote: teach show to display remote
HEAD, 2009-02-25) and e5dcbfd9ab7 (builtin-remote: new show output
style for push refspecs, 2009-02-25) we added some more of these.
As it turns out we only initialized this struct three times, all the
other uses were of pointers to those initialized structs. So let's
initialize it in those three places, skip the memset(), and pass those
structs down appropriately.
This would be a behavior change if we had codepaths that relied say on
implicitly having had "new_refs" initialized to STRING_LIST_INIT_NODUP
with the memset(), but only set the "strdup_strings" on some other
struct, but then called string_list_append() on "new_refs". There
isn't any such codepath, all of the late assignments to
"strdup_strings" assigned to those structs that we'd use for those
codepaths.
So just initializing them all up-front makes for easier to understand
code, i.e. in the pre-image it looked as though we had that tricky
edge case, but we didn't.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-10-01 10:27:34 +00:00
|
|
|
#define REF_STATES_INIT { \
|
|
|
|
.new_refs = STRING_LIST_INIT_DUP, \
|
2022-06-17 00:20:31 +00:00
|
|
|
.skipped = STRING_LIST_INIT_DUP, \
|
builtin/remote.c: add and use a REF_STATES_INIT
Use a new REF_STATES_INIT designated initializer instead of assigning
to the "strdup_strings" member of the previously memzero()'d version
of this struct.
The pattern of assigning to "strdup_strings" dates back to
211c89682ee (Make git-remote a builtin, 2008-02-29) (when it was
"strdup_paths"), i.e. long before we used anything like our current
established *_INIT patterns consistently.
Then in e61e0cc6b70 (builtin-remote: teach show to display remote
HEAD, 2009-02-25) and e5dcbfd9ab7 (builtin-remote: new show output
style for push refspecs, 2009-02-25) we added some more of these.
As it turns out we only initialized this struct three times, all the
other uses were of pointers to those initialized structs. So let's
initialize it in those three places, skip the memset(), and pass those
structs down appropriately.
This would be a behavior change if we had codepaths that relied say on
implicitly having had "new_refs" initialized to STRING_LIST_INIT_NODUP
with the memset(), but only set the "strdup_strings" on some other
struct, but then called string_list_append() on "new_refs". There
isn't any such codepath, all of the late assignments to
"strdup_strings" assigned to those structs that we'd use for those
codepaths.
So just initializing them all up-front makes for easier to understand
code, i.e. in the pre-image it looked as though we had that tricky
edge case, but we didn't.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-10-01 10:27:34 +00:00
|
|
|
.stale = STRING_LIST_INIT_DUP, \
|
|
|
|
.tracked = STRING_LIST_INIT_DUP, \
|
|
|
|
.heads = STRING_LIST_INIT_DUP, \
|
|
|
|
.push = STRING_LIST_INIT_DUP, \
|
|
|
|
}
|
|
|
|
|
2009-02-25 08:32:21 +00:00
|
|
|
static int get_ref_states(const struct ref *remote_refs, struct ref_states *states)
|
2008-02-29 01:45:45 +00:00
|
|
|
{
|
|
|
|
struct ref *fetch_map = NULL, **tail = &fetch_map;
|
2009-11-10 05:03:31 +00:00
|
|
|
struct ref *ref, *stale_refs;
|
2008-02-29 01:45:45 +00:00
|
|
|
int i;
|
|
|
|
|
2018-05-16 22:58:01 +00:00
|
|
|
for (i = 0; i < states->remote->fetch.nr; i++)
|
|
|
|
if (get_fetch_map(remote_refs, &states->remote->fetch.items[i], &tail, 1))
|
2012-04-23 12:30:26 +00:00
|
|
|
die(_("Could not get fetch map for refspec %s"),
|
2018-05-16 22:58:01 +00:00
|
|
|
states->remote->fetch.raw[i]);
|
2008-02-29 01:45:45 +00:00
|
|
|
|
|
|
|
for (ref = fetch_map; ref; ref = ref->next) {
|
2022-06-17 00:20:31 +00:00
|
|
|
if (omit_name_by_refspec(ref->name, &states->remote->fetch))
|
|
|
|
string_list_append(&states->skipped, abbrev_branch(ref->name));
|
2024-05-07 07:11:53 +00:00
|
|
|
else if (!ref->peer_ref || !refs_ref_exists(get_main_ref_store(the_repository), ref->peer_ref->name))
|
2018-02-14 18:59:35 +00:00
|
|
|
string_list_append(&states->new_refs, abbrev_branch(ref->name));
|
2009-02-25 08:32:20 +00:00
|
|
|
else
|
2010-06-25 23:41:38 +00:00
|
|
|
string_list_append(&states->tracked, abbrev_branch(ref->name));
|
2008-02-29 01:45:45 +00:00
|
|
|
}
|
2018-05-16 22:58:10 +00:00
|
|
|
stale_refs = get_stale_heads(&states->remote->fetch, fetch_map);
|
2009-11-10 05:03:31 +00:00
|
|
|
for (ref = stale_refs; ref; ref = ref->next) {
|
|
|
|
struct string_list_item *item =
|
2010-06-25 23:41:38 +00:00
|
|
|
string_list_append(&states->stale, abbrev_branch(ref->name));
|
2009-11-10 05:03:31 +00:00
|
|
|
item->util = xstrdup(ref->name);
|
|
|
|
}
|
|
|
|
free_refs(stale_refs);
|
2008-02-29 01:45:45 +00:00
|
|
|
free_refs(fetch_map);
|
|
|
|
|
2018-02-14 18:59:35 +00:00
|
|
|
string_list_sort(&states->new_refs);
|
2022-06-17 00:20:31 +00:00
|
|
|
string_list_sort(&states->skipped);
|
2014-11-25 08:02:35 +00:00
|
|
|
string_list_sort(&states->tracked);
|
|
|
|
string_list_sort(&states->stale);
|
2008-02-29 01:45:45 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-02-25 08:32:28 +00:00
|
|
|
struct push_info {
|
|
|
|
char *dest;
|
|
|
|
int forced;
|
|
|
|
enum {
|
|
|
|
PUSH_STATUS_CREATE = 0,
|
|
|
|
PUSH_STATUS_DELETE,
|
|
|
|
PUSH_STATUS_UPTODATE,
|
|
|
|
PUSH_STATUS_FASTFORWARD,
|
|
|
|
PUSH_STATUS_OUTOFDATE,
|
2010-05-14 09:31:35 +00:00
|
|
|
PUSH_STATUS_NOTQUERIED
|
2009-02-25 08:32:28 +00:00
|
|
|
} status;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int get_push_ref_states(const struct ref *remote_refs,
|
|
|
|
struct ref_states *states)
|
|
|
|
{
|
|
|
|
struct remote *remote = states->remote;
|
2009-05-31 14:26:48 +00:00
|
|
|
struct ref *ref, *local_refs, *push_map;
|
2009-02-25 08:32:28 +00:00
|
|
|
if (remote->mirror)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
local_refs = get_local_heads();
|
2009-05-27 20:13:43 +00:00
|
|
|
push_map = copy_ref_list(remote_refs);
|
2009-02-25 08:32:28 +00:00
|
|
|
|
2018-05-16 22:58:21 +00:00
|
|
|
match_push_refs(local_refs, &push_map, &remote->push, MATCH_REFS_NONE);
|
2009-02-25 08:32:28 +00:00
|
|
|
|
|
|
|
for (ref = push_map; ref; ref = ref->next) {
|
|
|
|
struct string_list_item *item;
|
|
|
|
struct push_info *info;
|
|
|
|
|
|
|
|
if (!ref->peer_ref)
|
|
|
|
continue;
|
2015-11-10 02:22:20 +00:00
|
|
|
oidcpy(&ref->new_oid, &ref->peer_ref->new_oid);
|
2009-02-25 08:32:28 +00:00
|
|
|
|
2010-06-25 23:41:38 +00:00
|
|
|
item = string_list_append(&states->push,
|
|
|
|
abbrev_branch(ref->peer_ref->name));
|
2014-05-26 15:33:44 +00:00
|
|
|
item->util = xcalloc(1, sizeof(struct push_info));
|
2009-02-25 08:32:28 +00:00
|
|
|
info = item->util;
|
|
|
|
info->forced = ref->force;
|
|
|
|
info->dest = xstrdup(abbrev_branch(ref->name));
|
|
|
|
|
2015-11-10 02:22:20 +00:00
|
|
|
if (is_null_oid(&ref->new_oid)) {
|
2009-02-25 08:32:28 +00:00
|
|
|
info->status = PUSH_STATUS_DELETE;
|
convert "oidcmp() == 0" to oideq()
Using the more restrictive oideq() should, in the long run,
give the compiler more opportunities to optimize these
callsites. For now, this conversion should be a complete
noop with respect to the generated code.
The result is also perhaps a little more readable, as it
avoids the "zero is equal" idiom. Since it's so prevalent in
C, I think seasoned programmers tend not to even notice it
anymore, but it can sometimes make for awkward double
negations (e.g., we can drop a few !!oidcmp() instances
here).
This patch was generated almost entirely by the included
coccinelle patch. This mechanical conversion should be
completely safe, because we check explicitly for cases where
oidcmp() is compared to 0, which is what oideq() is doing
under the hood. Note that we don't have to catch "!oidcmp()"
separately; coccinelle's standard isomorphisms make sure the
two are treated equivalently.
I say "almost" because I did hand-edit the coccinelle output
to fix up a few style violations (it mostly keeps the
original formatting, but sometimes unwraps long lines).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-28 21:22:40 +00:00
|
|
|
} else if (oideq(&ref->old_oid, &ref->new_oid))
|
2009-02-25 08:32:28 +00:00
|
|
|
info->status = PUSH_STATUS_UPTODATE;
|
2015-11-10 02:22:20 +00:00
|
|
|
else if (is_null_oid(&ref->old_oid))
|
2009-02-25 08:32:28 +00:00
|
|
|
info->status = PUSH_STATUS_CREATE;
|
2023-03-28 13:58:50 +00:00
|
|
|
else if (repo_has_object_file(the_repository, &ref->old_oid) &&
|
2015-11-10 02:22:25 +00:00
|
|
|
ref_newer(&ref->new_oid, &ref->old_oid))
|
2009-02-25 08:32:28 +00:00
|
|
|
info->status = PUSH_STATUS_FASTFORWARD;
|
|
|
|
else
|
|
|
|
info->status = PUSH_STATUS_OUTOFDATE;
|
|
|
|
}
|
|
|
|
free_refs(local_refs);
|
|
|
|
free_refs(push_map);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_push_ref_states_noquery(struct ref_states *states)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct remote *remote = states->remote;
|
|
|
|
struct string_list_item *item;
|
|
|
|
struct push_info *info;
|
|
|
|
|
|
|
|
if (remote->mirror)
|
|
|
|
return 0;
|
|
|
|
|
2018-05-16 22:58:00 +00:00
|
|
|
if (!remote->push.nr) {
|
2012-04-23 12:30:26 +00:00
|
|
|
item = string_list_append(&states->push, _("(matching)"));
|
2014-05-26 15:33:44 +00:00
|
|
|
info = item->util = xcalloc(1, sizeof(struct push_info));
|
2009-02-25 08:32:28 +00:00
|
|
|
info->status = PUSH_STATUS_NOTQUERIED;
|
|
|
|
info->dest = xstrdup(item->string);
|
|
|
|
}
|
2018-05-16 22:58:00 +00:00
|
|
|
for (i = 0; i < remote->push.nr; i++) {
|
|
|
|
const struct refspec_item *spec = &remote->push.items[i];
|
2009-02-25 08:32:28 +00:00
|
|
|
if (spec->matching)
|
2012-04-23 12:30:26 +00:00
|
|
|
item = string_list_append(&states->push, _("(matching)"));
|
2009-03-08 08:12:33 +00:00
|
|
|
else if (strlen(spec->src))
|
2010-06-25 23:41:38 +00:00
|
|
|
item = string_list_append(&states->push, spec->src);
|
2009-02-25 08:32:28 +00:00
|
|
|
else
|
2012-04-23 12:30:26 +00:00
|
|
|
item = string_list_append(&states->push, _("(delete)"));
|
2009-02-25 08:32:28 +00:00
|
|
|
|
2014-05-26 15:33:44 +00:00
|
|
|
info = item->util = xcalloc(1, sizeof(struct push_info));
|
2009-02-25 08:32:28 +00:00
|
|
|
info->forced = spec->force;
|
|
|
|
info->status = PUSH_STATUS_NOTQUERIED;
|
2009-03-08 08:12:33 +00:00
|
|
|
info->dest = xstrdup(spec->dst ? spec->dst : item->string);
|
2009-02-25 08:32:28 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-02-25 08:32:24 +00:00
|
|
|
static int get_head_names(const struct ref *remote_refs, struct ref_states *states)
|
|
|
|
{
|
|
|
|
struct ref *ref, *matches;
|
|
|
|
struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
|
builtin/remote: cast away constness in `get_head_names()`
In `get_head_names()`, we assign the "refs/heads/*" string constant to
`struct refspec_item::{src,dst}`, which are both non-constant pointers.
Ideally, we'd refactor the code such that both of these fields were
constant. But `struct refspec_item` is used for two different usecases
with conflicting requirements:
- To query for a source or destination based on the given refspec. The
caller either sets `src` or `dst` as the branch that we want to
search for, and the respective other field gets populated. The
fields should be constant when being used as a query parameter,
which is owned by the caller, and non-constant when being used as an
out parameter, which is owned by the refspec item. This is is
contradictory in itself already.
- To store refspec items with their respective source and destination
branches, in which case both fields should be owned by the struct.
Ideally, we'd split up this interface to clearly separate between
querying and storing, which would enable us to clarify lifetimes of the
strings. This would be a much bigger undertaking though.
Instead, accept the status quo for now and cast away the constness of
the source and destination patterns. We know that those are not being
written to or freed, so while this is ugly it certainly is fine for now.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-07 06:38:02 +00:00
|
|
|
struct refspec_item refspec = {
|
|
|
|
.force = 0,
|
|
|
|
.pattern = 1,
|
|
|
|
.src = (char *) "refs/heads/*",
|
|
|
|
.dst = (char *) "refs/heads/*",
|
|
|
|
};
|
2009-02-25 08:32:24 +00:00
|
|
|
|
|
|
|
get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);
|
|
|
|
matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"),
|
|
|
|
fetch_map, 1);
|
2009-09-01 05:35:10 +00:00
|
|
|
for (ref = matches; ref; ref = ref->next)
|
2010-06-25 23:41:38 +00:00
|
|
|
string_list_append(&states->heads, abbrev_branch(ref->name));
|
2009-02-25 08:32:24 +00:00
|
|
|
|
|
|
|
free_refs(fetch_map);
|
|
|
|
free_refs(matches);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-06-01 04:28:04 +00:00
|
|
|
struct known_remote {
|
|
|
|
struct known_remote *next;
|
|
|
|
struct remote *remote;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct known_remotes {
|
|
|
|
struct remote *to_delete;
|
|
|
|
struct known_remote *list;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int add_known_remote(struct remote *remote, void *cb_data)
|
|
|
|
{
|
|
|
|
struct known_remotes *all = cb_data;
|
|
|
|
struct known_remote *r;
|
|
|
|
|
|
|
|
if (!strcmp(all->to_delete->name, remote->name))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = xmalloc(sizeof(*r));
|
|
|
|
r->remote = remote;
|
|
|
|
r->next = all->list;
|
|
|
|
all->list = r;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-29 01:45:45 +00:00
|
|
|
struct branches_for_remote {
|
2008-06-01 04:28:04 +00:00
|
|
|
struct remote *remote;
|
2009-02-04 16:06:07 +00:00
|
|
|
struct string_list *branches, *skipped;
|
2008-06-01 04:28:04 +00:00
|
|
|
struct known_remotes *keep;
|
2008-02-29 01:45:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int add_branch_for_removal(const char *refname,
|
2024-08-09 15:37:50 +00:00
|
|
|
const char *referent UNUSED,
|
2022-08-25 17:09:48 +00:00
|
|
|
const struct object_id *oid UNUSED,
|
|
|
|
int flags UNUSED, void *cb_data)
|
2008-02-29 01:45:45 +00:00
|
|
|
{
|
|
|
|
struct branches_for_remote *branches = cb_data;
|
2018-05-16 22:57:49 +00:00
|
|
|
struct refspec_item refspec;
|
2008-06-01 04:28:04 +00:00
|
|
|
struct known_remote *kr;
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2008-06-01 04:28:04 +00:00
|
|
|
memset(&refspec, 0, sizeof(refspec));
|
|
|
|
refspec.dst = (char *)refname;
|
|
|
|
if (remote_find_tracking(branches->remote, &refspec))
|
|
|
|
return 0;
|
2024-08-01 10:40:12 +00:00
|
|
|
free(refspec.src);
|
2008-06-01 04:28:04 +00:00
|
|
|
|
|
|
|
/* don't delete a branch if another remote also uses it */
|
|
|
|
for (kr = branches->keep->list; kr; kr = kr->next) {
|
|
|
|
memset(&refspec, 0, sizeof(refspec));
|
|
|
|
refspec.dst = (char *)refname;
|
2024-08-01 10:40:12 +00:00
|
|
|
if (!remote_find_tracking(kr->remote, &refspec)) {
|
|
|
|
free(refspec.src);
|
2008-06-01 04:28:04 +00:00
|
|
|
return 0;
|
2024-08-01 10:40:12 +00:00
|
|
|
}
|
2008-06-01 04:28:04 +00:00
|
|
|
}
|
2008-03-08 22:40:42 +00:00
|
|
|
|
2010-11-02 15:31:25 +00:00
|
|
|
/* don't delete non-remote-tracking refs */
|
2013-11-30 20:55:40 +00:00
|
|
|
if (!starts_with(refname, "refs/remotes/")) {
|
2009-02-04 16:06:07 +00:00
|
|
|
/* advise user how to delete local branches */
|
2013-11-30 20:55:40 +00:00
|
|
|
if (starts_with(refname, "refs/heads/"))
|
2010-06-25 23:41:38 +00:00
|
|
|
string_list_append(branches->skipped,
|
|
|
|
abbrev_branch(refname));
|
2009-02-04 16:06:07 +00:00
|
|
|
/* silently skip over other non-remote refs */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-25 18:38:42 +00:00
|
|
|
string_list_append(branches->branches, refname);
|
2008-02-29 01:45:45 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-03 18:26:18 +00:00
|
|
|
struct rename_info {
|
2018-02-14 18:59:35 +00:00
|
|
|
const char *old_name;
|
|
|
|
const char *new_name;
|
2008-11-03 18:26:18 +00:00
|
|
|
struct string_list *remote_branches;
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
uint32_t symrefs_nr;
|
2008-11-03 18:26:18 +00:00
|
|
|
};
|
|
|
|
|
2024-08-09 15:37:50 +00:00
|
|
|
static int read_remote_branches(const char *refname, const char *referent UNUSED,
|
2022-08-25 17:09:48 +00:00
|
|
|
const struct object_id *oid UNUSED,
|
|
|
|
int flags UNUSED, void *cb_data)
|
2008-11-03 18:26:18 +00:00
|
|
|
{
|
|
|
|
struct rename_info *rename = cb_data;
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
struct string_list_item *item;
|
|
|
|
int flag;
|
|
|
|
const char *symref;
|
|
|
|
|
2018-02-14 18:59:35 +00:00
|
|
|
strbuf_addf(&buf, "refs/remotes/%s/", rename->old_name);
|
2013-11-30 20:55:40 +00:00
|
|
|
if (starts_with(refname, buf.buf)) {
|
2018-08-01 10:19:07 +00:00
|
|
|
item = string_list_append(rename->remote_branches, refname);
|
2024-05-07 07:11:53 +00:00
|
|
|
symref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
|
|
|
|
refname, RESOLVE_REF_READING,
|
|
|
|
NULL, &flag);
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
if (symref && (flag & REF_ISSYMREF)) {
|
2008-11-03 18:26:18 +00:00
|
|
|
item->util = xstrdup(symref);
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
rename->symrefs_nr++;
|
|
|
|
} else {
|
2008-11-03 18:26:18 +00:00
|
|
|
item->util = NULL;
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
}
|
2008-11-03 18:26:18 +00:00
|
|
|
}
|
2017-08-30 18:00:25 +00:00
|
|
|
strbuf_release(&buf);
|
2008-11-03 18:26:18 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-10 20:43:01 +00:00
|
|
|
static int migrate_file(struct remote *remote)
|
|
|
|
{
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
strbuf_addf(&buf, "remote.%s.url", remote->name);
|
2024-06-14 10:28:01 +00:00
|
|
|
for (i = 0; i < remote->url.nr; i++)
|
|
|
|
git_config_set_multivar(buf.buf, remote->url.v[i], "^$", 0);
|
2008-11-10 20:43:01 +00:00
|
|
|
strbuf_reset(&buf);
|
|
|
|
strbuf_addf(&buf, "remote.%s.push", remote->name);
|
2018-05-16 22:58:00 +00:00
|
|
|
for (i = 0; i < remote->push.raw_nr; i++)
|
|
|
|
git_config_set_multivar(buf.buf, remote->push.raw[i], "^$", 0);
|
2008-11-10 20:43:01 +00:00
|
|
|
strbuf_reset(&buf);
|
|
|
|
strbuf_addf(&buf, "remote.%s.fetch", remote->name);
|
2018-05-16 22:58:01 +00:00
|
|
|
for (i = 0; i < remote->fetch.raw_nr; i++)
|
|
|
|
git_config_set_multivar(buf.buf, remote->fetch.raw[i], "^$", 0);
|
2008-11-10 20:43:01 +00:00
|
|
|
if (remote->origin == REMOTE_REMOTES)
|
2015-08-10 09:35:49 +00:00
|
|
|
unlink_or_warn(git_path("remotes/%s", remote->name));
|
2008-11-10 20:43:01 +00:00
|
|
|
else if (remote->origin == REMOTE_BRANCHES)
|
2015-08-10 09:35:49 +00:00
|
|
|
unlink_or_warn(git_path("branches/%s", remote->name));
|
2017-08-30 18:00:26 +00:00
|
|
|
strbuf_release(&buf);
|
2016-02-22 11:23:30 +00:00
|
|
|
|
2008-11-10 20:43:01 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-02-01 09:34:09 +00:00
|
|
|
struct push_default_info
|
|
|
|
{
|
|
|
|
const char *old_name;
|
|
|
|
enum config_scope scope;
|
|
|
|
struct strbuf origin;
|
|
|
|
int linenr;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int config_read_push_default(const char *key, const char *value,
|
2023-06-28 19:26:23 +00:00
|
|
|
const struct config_context *ctx, void *cb)
|
2020-02-01 09:34:09 +00:00
|
|
|
{
|
2023-06-28 19:26:23 +00:00
|
|
|
const struct key_value_info *kvi = ctx->kvi;
|
|
|
|
|
2020-02-01 09:34:09 +00:00
|
|
|
struct push_default_info* info = cb;
|
|
|
|
if (strcmp(key, "remote.pushdefault") ||
|
|
|
|
!value || strcmp(value, info->old_name))
|
|
|
|
return 0;
|
|
|
|
|
2023-06-28 19:26:23 +00:00
|
|
|
info->scope = kvi->scope;
|
2020-02-01 09:34:09 +00:00
|
|
|
strbuf_reset(&info->origin);
|
2023-06-28 19:26:23 +00:00
|
|
|
strbuf_addstr(&info->origin, config_origin_type_name(kvi->origin_type));
|
|
|
|
info->linenr = kvi->linenr;
|
2020-02-01 09:34:09 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void handle_push_default(const char* old_name, const char* new_name)
|
|
|
|
{
|
|
|
|
struct push_default_info push_default = {
|
2024-08-01 10:40:12 +00:00
|
|
|
.old_name = old_name,
|
|
|
|
.scope = CONFIG_SCOPE_UNKNOWN,
|
|
|
|
.origin = STRBUF_INIT,
|
|
|
|
.linenr = -1,
|
|
|
|
};
|
2020-02-01 09:34:09 +00:00
|
|
|
git_config(config_read_push_default, &push_default);
|
|
|
|
if (push_default.scope >= CONFIG_SCOPE_COMMAND)
|
|
|
|
; /* pass */
|
|
|
|
else if (push_default.scope >= CONFIG_SCOPE_LOCAL) {
|
|
|
|
int result = git_config_set_gently("remote.pushDefault",
|
|
|
|
new_name);
|
|
|
|
if (new_name && result && result != CONFIG_NOTHING_SET)
|
|
|
|
die(_("could not set '%s'"), "remote.pushDefault");
|
|
|
|
else if (!new_name && result && result != CONFIG_NOTHING_SET)
|
|
|
|
die(_("could not unset '%s'"), "remote.pushDefault");
|
|
|
|
} else if (push_default.scope >= CONFIG_SCOPE_SYSTEM) {
|
|
|
|
/* warn */
|
|
|
|
warning(_("The %s configuration remote.pushDefault in:\n"
|
|
|
|
"\t%s:%d\n"
|
|
|
|
"now names the non-existent remote '%s'"),
|
|
|
|
config_scope_name(push_default.scope),
|
|
|
|
push_default.origin.buf, push_default.linenr,
|
|
|
|
old_name);
|
|
|
|
}
|
2024-08-01 10:40:12 +00:00
|
|
|
|
|
|
|
strbuf_release(&push_default.origin);
|
2020-02-01 09:34:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-08-19 16:04:08 +00:00
|
|
|
static int mv(int argc, const char **argv, const char *prefix)
|
2008-11-03 18:26:18 +00:00
|
|
|
{
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
int show_progress = isatty(2);
|
2008-11-03 18:26:18 +00:00
|
|
|
struct option options[] = {
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
OPT_BOOL(0, "progress", &show_progress, N_("force progress reporting")),
|
2008-11-03 18:26:18 +00:00
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
struct remote *oldremote, *newremote;
|
2011-09-02 00:50:33 +00:00
|
|
|
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT,
|
|
|
|
old_remote_context = STRBUF_INIT;
|
2018-08-01 10:19:07 +00:00
|
|
|
struct string_list remote_branches = STRING_LIST_INIT_DUP;
|
2008-11-03 18:26:18 +00:00
|
|
|
struct rename_info rename;
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
int i, refs_renamed_nr = 0, refspec_updated = 0;
|
|
|
|
struct progress *progress = NULL;
|
2008-11-03 18:26:18 +00:00
|
|
|
|
pass subcommand "prefix" arguments to parse_options()
Recent commits such as bf0a6b65fc (builtin/multi-pack-index.c: let
parse-options parse subcommands, 2022-08-19) converted a few functions
to match our usual argc/argv/prefix conventions, but the prefix argument
remains unused.
However, there is a good use for it: they should pass it to their own
parse_options() functions, where it may be used to adjust the value of
any filename options. In all but one of these functions, there's no
behavior change, since they don't use OPT_FILENAME. But this is an
actual fix for one option, which you can see by modifying the test suite
like so:
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 4fe57414c1..d0974d4371 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -186,7 +186,11 @@ test_expect_success 'writing a bitmap with --refs-snapshot' '
# Then again, but with a refs snapshot which only sees
# refs/tags/one.
- git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
+ (
+ mkdir subdir &&
+ cd subdir &&
+ git multi-pack-index write --bitmap --refs-snapshot=../snapshot
+ ) &&
test_path_is_file $midx &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
I'd emphasize that this wasn't broken by bf0a6b65fc; it has been broken
all along, because the sub-function never got to see the prefix. It is
that commit which is actually enabling us to fix it (and which also
brought attention to the problem because it triggers -Wunused-parameter!)
The other functions changed here don't use OPT_FILENAME at all. In their
cases this isn't fixing anything visible, but it's following the usual
pattern and future-proofing them against somebody adding new options and
being surprised.
I didn't include a test for the one visible case above. We don't
generally test routine parse-options behavior for individual options.
The challenge here was finding the problem, and now that this has been
done, it's not likely to regress. Likewise, we could apply the patch
above to cover it "for free" but it makes reading the rest of the test
unnecessarily complicated.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-08-25 10:47:00 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, options,
|
2022-03-03 22:25:16 +00:00
|
|
|
builtin_remote_rename_usage, 0);
|
|
|
|
|
|
|
|
if (argc != 2)
|
2009-11-20 23:43:13 +00:00
|
|
|
usage_with_options(builtin_remote_rename_usage, options);
|
2008-11-03 18:26:18 +00:00
|
|
|
|
2022-03-03 22:25:16 +00:00
|
|
|
rename.old_name = argv[0];
|
|
|
|
rename.new_name = argv[1];
|
2008-11-03 18:26:18 +00:00
|
|
|
rename.remote_branches = &remote_branches;
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
rename.symrefs_nr = 0;
|
2008-11-03 18:26:18 +00:00
|
|
|
|
2018-02-14 18:59:35 +00:00
|
|
|
oldremote = remote_get(rename.old_name);
|
2020-10-27 09:41:36 +00:00
|
|
|
if (!remote_is_configured(oldremote, 1)) {
|
|
|
|
error(_("No such remote: '%s'"), rename.old_name);
|
|
|
|
exit(2);
|
|
|
|
}
|
2008-11-03 18:26:18 +00:00
|
|
|
|
2018-02-14 18:59:35 +00:00
|
|
|
if (!strcmp(rename.old_name, rename.new_name) && oldremote->origin != REMOTE_CONFIG)
|
2008-11-10 20:43:01 +00:00
|
|
|
return migrate_file(oldremote);
|
|
|
|
|
2018-02-14 18:59:35 +00:00
|
|
|
newremote = remote_get(rename.new_name);
|
2020-10-27 09:41:36 +00:00
|
|
|
if (remote_is_configured(newremote, 1)) {
|
|
|
|
error(_("remote %s already exists."), rename.new_name);
|
|
|
|
exit(3);
|
|
|
|
}
|
2008-11-03 18:26:18 +00:00
|
|
|
|
2020-10-01 03:46:13 +00:00
|
|
|
if (!valid_remote_name(rename.new_name))
|
2018-02-14 18:59:35 +00:00
|
|
|
die(_("'%s' is not a valid remote name"), rename.new_name);
|
2008-11-03 18:26:18 +00:00
|
|
|
|
2018-02-14 18:59:35 +00:00
|
|
|
strbuf_addf(&buf, "remote.%s", rename.old_name);
|
|
|
|
strbuf_addf(&buf2, "remote.%s", rename.new_name);
|
2008-11-03 18:26:18 +00:00
|
|
|
if (git_config_rename_section(buf.buf, buf2.buf) < 1)
|
2012-04-23 12:30:26 +00:00
|
|
|
return error(_("Could not rename config section '%s' to '%s'"),
|
2008-11-03 18:26:18 +00:00
|
|
|
buf.buf, buf2.buf);
|
|
|
|
|
2022-09-22 05:33:29 +00:00
|
|
|
if (oldremote->fetch.raw_nr) {
|
|
|
|
strbuf_reset(&buf);
|
|
|
|
strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
|
|
|
|
git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
|
|
|
|
strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
|
|
|
|
for (i = 0; i < oldremote->fetch.raw_nr; i++) {
|
|
|
|
char *ptr;
|
|
|
|
|
|
|
|
strbuf_reset(&buf2);
|
|
|
|
strbuf_addstr(&buf2, oldremote->fetch.raw[i]);
|
|
|
|
ptr = strstr(buf2.buf, old_remote_context.buf);
|
|
|
|
if (ptr) {
|
|
|
|
refspec_updated = 1;
|
|
|
|
strbuf_splice(&buf2,
|
|
|
|
ptr-buf2.buf + strlen(":refs/remotes/"),
|
|
|
|
strlen(rename.old_name), rename.new_name,
|
|
|
|
strlen(rename.new_name));
|
|
|
|
} else
|
|
|
|
warning(_("Not updating non-default fetch refspec\n"
|
|
|
|
"\t%s\n"
|
|
|
|
"\tPlease update the configuration manually if necessary."),
|
|
|
|
buf2.buf);
|
|
|
|
|
|
|
|
git_config_set_multivar(buf.buf, buf2.buf, "^$", 0);
|
|
|
|
}
|
2008-11-03 18:26:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
read_branches();
|
|
|
|
for (i = 0; i < branch_list.nr; i++) {
|
|
|
|
struct string_list_item *item = branch_list.items + i;
|
|
|
|
struct branch_info *info = item->util;
|
2018-02-14 18:59:35 +00:00
|
|
|
if (info->remote_name && !strcmp(info->remote_name, rename.old_name)) {
|
2008-11-03 18:26:18 +00:00
|
|
|
strbuf_reset(&buf);
|
|
|
|
strbuf_addf(&buf, "branch.%s.remote", item->string);
|
2018-02-14 18:59:35 +00:00
|
|
|
git_config_set(buf.buf, rename.new_name);
|
2008-11-03 18:26:18 +00:00
|
|
|
}
|
2020-01-27 07:04:30 +00:00
|
|
|
if (info->push_remote_name && !strcmp(info->push_remote_name, rename.old_name)) {
|
|
|
|
strbuf_reset(&buf);
|
2021-02-25 01:21:17 +00:00
|
|
|
strbuf_addf(&buf, "branch.%s.pushRemote", item->string);
|
2020-01-27 07:04:30 +00:00
|
|
|
git_config_set(buf.buf, rename.new_name);
|
|
|
|
}
|
2008-11-03 18:26:18 +00:00
|
|
|
}
|
|
|
|
|
2011-09-10 19:39:23 +00:00
|
|
|
if (!refspec_updated)
|
2024-08-01 10:40:12 +00:00
|
|
|
goto out;
|
2011-09-10 19:39:23 +00:00
|
|
|
|
2008-11-03 18:26:18 +00:00
|
|
|
/*
|
|
|
|
* First remove symrefs, then rename the rest, finally create
|
|
|
|
* the new symrefs.
|
|
|
|
*/
|
2024-05-07 07:11:53 +00:00
|
|
|
refs_for_each_ref(get_main_ref_store(the_repository),
|
|
|
|
read_remote_branches, &rename);
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
if (show_progress) {
|
|
|
|
/*
|
|
|
|
* Count symrefs twice, since "renaming" them is done by
|
|
|
|
* deleting and recreating them in two separate passes.
|
|
|
|
*/
|
|
|
|
progress = start_progress(_("Renaming remote references"),
|
|
|
|
rename.remote_branches->nr + rename.symrefs_nr);
|
|
|
|
}
|
2008-11-03 18:26:18 +00:00
|
|
|
for (i = 0; i < remote_branches.nr; i++) {
|
|
|
|
struct string_list_item *item = remote_branches.items + i;
|
2022-03-01 09:33:50 +00:00
|
|
|
struct strbuf referent = STRBUF_INIT;
|
2008-11-03 18:26:18 +00:00
|
|
|
|
2022-03-01 09:33:50 +00:00
|
|
|
if (refs_read_symbolic_ref(get_main_ref_store(the_repository), item->string,
|
|
|
|
&referent))
|
2008-11-03 18:26:18 +00:00
|
|
|
continue;
|
2024-05-07 07:11:53 +00:00
|
|
|
if (refs_delete_ref(get_main_ref_store(the_repository), NULL, item->string, NULL, REF_NO_DEREF))
|
2012-04-23 12:30:26 +00:00
|
|
|
die(_("deleting '%s' failed"), item->string);
|
2022-03-01 09:33:50 +00:00
|
|
|
|
|
|
|
strbuf_release(&referent);
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
display_progress(progress, ++refs_renamed_nr);
|
2008-11-03 18:26:18 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < remote_branches.nr; i++) {
|
|
|
|
struct string_list_item *item = remote_branches.items + i;
|
|
|
|
|
|
|
|
if (item->util)
|
|
|
|
continue;
|
|
|
|
strbuf_reset(&buf);
|
|
|
|
strbuf_addstr(&buf, item->string);
|
2018-02-14 18:59:35 +00:00
|
|
|
strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old_name),
|
|
|
|
rename.new_name, strlen(rename.new_name));
|
2008-11-03 18:26:18 +00:00
|
|
|
strbuf_reset(&buf2);
|
|
|
|
strbuf_addf(&buf2, "remote: renamed %s to %s",
|
|
|
|
item->string, buf.buf);
|
2024-05-07 07:11:53 +00:00
|
|
|
if (refs_rename_ref(get_main_ref_store(the_repository), item->string, buf.buf, buf2.buf))
|
2012-04-23 12:30:26 +00:00
|
|
|
die(_("renaming '%s' failed"), item->string);
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
display_progress(progress, ++refs_renamed_nr);
|
2008-11-03 18:26:18 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < remote_branches.nr; i++) {
|
|
|
|
struct string_list_item *item = remote_branches.items + i;
|
|
|
|
|
|
|
|
if (!item->util)
|
|
|
|
continue;
|
|
|
|
strbuf_reset(&buf);
|
|
|
|
strbuf_addstr(&buf, item->string);
|
2018-02-14 18:59:35 +00:00
|
|
|
strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old_name),
|
|
|
|
rename.new_name, strlen(rename.new_name));
|
2008-11-03 18:26:18 +00:00
|
|
|
strbuf_reset(&buf2);
|
|
|
|
strbuf_addstr(&buf2, item->util);
|
2018-02-14 18:59:35 +00:00
|
|
|
strbuf_splice(&buf2, strlen("refs/remotes/"), strlen(rename.old_name),
|
|
|
|
rename.new_name, strlen(rename.new_name));
|
2008-11-03 18:26:18 +00:00
|
|
|
strbuf_reset(&buf3);
|
|
|
|
strbuf_addf(&buf3, "remote: renamed %s to %s",
|
|
|
|
item->string, buf.buf);
|
2024-05-20 18:20:04 +00:00
|
|
|
if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, buf3.buf))
|
2012-04-23 12:30:26 +00:00
|
|
|
die(_("creating '%s' failed"), buf.buf);
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
display_progress(progress, ++refs_renamed_nr);
|
2008-11-03 18:26:18 +00:00
|
|
|
}
|
builtin/remote.c: show progress when renaming remote references
When renaming a remote, Git needs to rename all remote tracking
references to the remote's new name (e.g., renaming
"refs/remotes/old/foo" to "refs/remotes/new/foo" when renaming a remote
from "old" to "new").
This can be somewhat slow when there are many references to rename,
since each rename is done in a separate call to rename_ref() as opposed
to grouping all renames together into the same transaction. It would be
nice to execute all renames as a single transaction, but there is a
snag: the reference transaction backend doesn't support renames during a
transaction (only individually, via rename_ref()).
The reasons there are described in more detail in [1], but the main
problem is that in order to preserve the existing reflog, it must be
moved while holding both locks (i.e., on "oldname" and "newname"), and
the ref transaction code doesn't support inserting arbitrary actions
into the middle of a transaction like that.
As an aside, adding support for this to the ref transaction code is
less straightforward than inserting both a ref_update() and ref_delete()
call into the same transaction. rename_ref()'s special handling to
detect D/F conflicts would need to be rewritten for the transaction code
if we wanted to proactively catch D/F conflicts when renaming a
reference during a transaction. The reftable backend could support this
much more readily because of its lack of D/F conflicts.
Instead of a more complex modification to the ref transaction code,
display a progress meter when running verbosely in order to convince the
user that Git is doing work while renaming a remote.
This is mostly done as-expected, with the minor caveat that we
intentionally count symrefs renames twice, since renaming a symref takes
place over two separate calls (one to delete the old one, and another to
create the new one).
[1]: https://lore.kernel.org/git/572367B4.4050207@alum.mit.edu/
Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-03 22:25:18 +00:00
|
|
|
stop_progress(&progress);
|
2020-02-01 09:34:09 +00:00
|
|
|
|
|
|
|
handle_push_default(rename.old_name, rename.new_name);
|
|
|
|
|
2024-08-01 10:40:12 +00:00
|
|
|
out:
|
|
|
|
string_list_clear(&remote_branches, 1);
|
|
|
|
strbuf_release(&old_remote_context);
|
|
|
|
strbuf_release(&buf);
|
|
|
|
strbuf_release(&buf2);
|
|
|
|
strbuf_release(&buf3);
|
2008-11-03 18:26:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-19 16:04:08 +00:00
|
|
|
static int rm(int argc, const char **argv, const char *prefix)
|
2008-02-29 01:45:45 +00:00
|
|
|
{
|
|
|
|
struct option options[] = {
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
struct remote *remote;
|
2008-10-09 19:12:12 +00:00
|
|
|
struct strbuf buf = STRBUF_INIT;
|
2008-06-01 04:28:04 +00:00
|
|
|
struct known_remotes known_remotes = { NULL, NULL };
|
2010-07-04 19:46:19 +00:00
|
|
|
struct string_list branches = STRING_LIST_INIT_DUP;
|
|
|
|
struct string_list skipped = STRING_LIST_INIT_DUP;
|
2010-05-14 09:31:33 +00:00
|
|
|
struct branches_for_remote cb_data;
|
2009-02-03 17:51:12 +00:00
|
|
|
int i, result;
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2010-05-14 09:31:33 +00:00
|
|
|
memset(&cb_data, 0, sizeof(cb_data));
|
|
|
|
cb_data.branches = &branches;
|
|
|
|
cb_data.skipped = &skipped;
|
|
|
|
cb_data.keep = &known_remotes;
|
|
|
|
|
2022-08-25 10:51:40 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, options,
|
|
|
|
builtin_remote_rm_usage, 0);
|
|
|
|
if (argc != 1)
|
2009-11-20 23:43:13 +00:00
|
|
|
usage_with_options(builtin_remote_rm_usage, options);
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2022-08-25 10:51:40 +00:00
|
|
|
remote = remote_get(argv[0]);
|
2020-10-27 09:41:36 +00:00
|
|
|
if (!remote_is_configured(remote, 1)) {
|
2022-08-25 10:51:40 +00:00
|
|
|
error(_("No such remote: '%s'"), argv[0]);
|
2020-10-27 09:41:36 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2008-06-01 04:28:04 +00:00
|
|
|
known_remotes.to_delete = remote;
|
|
|
|
for_each_remote(add_known_remote, &known_remotes);
|
|
|
|
|
2008-02-29 01:45:45 +00:00
|
|
|
read_branches();
|
|
|
|
for (i = 0; i < branch_list.nr; i++) {
|
2008-07-21 18:03:49 +00:00
|
|
|
struct string_list_item *item = branch_list.items + i;
|
2008-02-29 01:45:45 +00:00
|
|
|
struct branch_info *info = item->util;
|
2009-02-25 08:32:21 +00:00
|
|
|
if (info->remote_name && !strcmp(info->remote_name, remote->name)) {
|
2008-02-29 01:45:45 +00:00
|
|
|
const char *keys[] = { "remote", "merge", NULL }, **k;
|
|
|
|
for (k = keys; *k; k++) {
|
|
|
|
strbuf_reset(&buf);
|
|
|
|
strbuf_addf(&buf, "branch.%s.%s",
|
2008-07-21 18:03:49 +00:00
|
|
|
item->string, *k);
|
2017-02-18 00:23:41 +00:00
|
|
|
result = git_config_set_gently(buf.buf, NULL);
|
|
|
|
if (result && result != CONFIG_NOTHING_SET)
|
|
|
|
die(_("could not unset '%s'"), buf.buf);
|
2008-02-29 01:45:45 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-27 07:04:30 +00:00
|
|
|
if (info->push_remote_name && !strcmp(info->push_remote_name, remote->name)) {
|
|
|
|
strbuf_reset(&buf);
|
|
|
|
strbuf_addf(&buf, "branch.%s.pushremote", item->string);
|
|
|
|
result = git_config_set_gently(buf.buf, NULL);
|
|
|
|
if (result && result != CONFIG_NOTHING_SET)
|
|
|
|
die(_("could not unset '%s'"), buf.buf);
|
|
|
|
}
|
2008-02-29 01:45:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We cannot just pass a function to for_each_ref() which deletes
|
|
|
|
* the branches one by one, since for_each_ref() relies on cached
|
|
|
|
* refs, which are invalidated when deleting a branch.
|
|
|
|
*/
|
2008-06-01 04:28:04 +00:00
|
|
|
cb_data.remote = remote;
|
2024-05-07 07:11:53 +00:00
|
|
|
result = refs_for_each_ref(get_main_ref_store(the_repository),
|
|
|
|
add_branch_for_removal, &cb_data);
|
2008-02-29 01:45:45 +00:00
|
|
|
strbuf_release(&buf);
|
|
|
|
|
2009-02-03 17:51:12 +00:00
|
|
|
if (!result)
|
2024-05-07 07:11:53 +00:00
|
|
|
result = refs_delete_refs(get_main_ref_store(the_repository),
|
|
|
|
"remote: remove", &branches,
|
|
|
|
REF_NO_DEREF);
|
2015-05-25 18:38:42 +00:00
|
|
|
string_list_clear(&branches, 0);
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2009-02-04 16:06:07 +00:00
|
|
|
if (skipped.nr) {
|
2012-04-23 12:30:26 +00:00
|
|
|
fprintf_ln(stderr,
|
|
|
|
Q_("Note: A branch outside the refs/remotes/ hierarchy was not removed;\n"
|
|
|
|
"to delete it, use:",
|
|
|
|
"Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n"
|
|
|
|
"to delete them, use:",
|
|
|
|
skipped.nr));
|
2009-02-04 16:06:07 +00:00
|
|
|
for (i = 0; i < skipped.nr; i++)
|
|
|
|
fprintf(stderr, " git branch -d %s\n",
|
|
|
|
skipped.items[i].string);
|
|
|
|
}
|
|
|
|
string_list_clear(&skipped, 0);
|
|
|
|
|
2014-05-23 10:28:43 +00:00
|
|
|
if (!result) {
|
|
|
|
strbuf_addf(&buf, "remote.%s", remote->name);
|
2024-08-01 10:40:12 +00:00
|
|
|
if (git_config_rename_section(buf.buf, NULL) < 1) {
|
|
|
|
result = error(_("Could not remove config section '%s'"), buf.buf);
|
|
|
|
goto out;
|
|
|
|
}
|
2020-02-01 09:34:09 +00:00
|
|
|
|
|
|
|
handle_push_default(remote->name, NULL);
|
2014-05-23 10:28:43 +00:00
|
|
|
}
|
|
|
|
|
2024-08-01 10:40:12 +00:00
|
|
|
out:
|
|
|
|
for (struct known_remote *r = known_remotes.list; r;) {
|
|
|
|
struct known_remote *next = r->next;
|
|
|
|
free(r);
|
|
|
|
r = next;
|
|
|
|
}
|
|
|
|
strbuf_release(&buf);
|
2009-02-03 17:51:12 +00:00
|
|
|
return result;
|
2008-02-29 01:45:45 +00:00
|
|
|
}
|
|
|
|
|
2022-10-18 01:05:32 +00:00
|
|
|
static void clear_push_info(void *util, const char *string UNUSED)
|
2008-02-29 01:45:45 +00:00
|
|
|
{
|
2009-02-25 08:32:28 +00:00
|
|
|
struct push_info *info = util;
|
|
|
|
free(info->dest);
|
|
|
|
free(info);
|
|
|
|
}
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2009-02-25 08:32:19 +00:00
|
|
|
static void free_remote_ref_states(struct ref_states *states)
|
|
|
|
{
|
2018-02-14 18:59:35 +00:00
|
|
|
string_list_clear(&states->new_refs, 0);
|
2022-06-17 00:20:31 +00:00
|
|
|
string_list_clear(&states->skipped, 0);
|
2009-11-30 23:57:27 +00:00
|
|
|
string_list_clear(&states->stale, 1);
|
2009-02-25 08:32:19 +00:00
|
|
|
string_list_clear(&states->tracked, 0);
|
2009-02-25 08:32:24 +00:00
|
|
|
string_list_clear(&states->heads, 0);
|
2009-02-25 08:32:28 +00:00
|
|
|
string_list_clear_func(&states->push, clear_push_info);
|
2009-02-25 08:32:19 +00:00
|
|
|
}
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2009-02-25 08:32:22 +00:00
|
|
|
static int append_ref_to_tracked_list(const char *refname,
|
2024-08-09 15:37:50 +00:00
|
|
|
const char *referent UNUSED,
|
2022-08-25 17:09:48 +00:00
|
|
|
const struct object_id *oid UNUSED,
|
2022-08-19 10:08:32 +00:00
|
|
|
int flags, void *cb_data)
|
2009-02-25 08:32:22 +00:00
|
|
|
{
|
|
|
|
struct ref_states *states = cb_data;
|
2018-05-16 22:57:49 +00:00
|
|
|
struct refspec_item refspec;
|
2009-02-25 08:32:22 +00:00
|
|
|
|
2009-02-25 08:32:23 +00:00
|
|
|
if (flags & REF_ISSYMREF)
|
|
|
|
return 0;
|
|
|
|
|
2009-02-25 08:32:22 +00:00
|
|
|
memset(&refspec, 0, sizeof(refspec));
|
|
|
|
refspec.dst = (char *)refname;
|
2024-08-01 10:40:12 +00:00
|
|
|
if (!remote_find_tracking(states->remote, &refspec)) {
|
2010-06-25 23:41:38 +00:00
|
|
|
string_list_append(&states->tracked, abbrev_branch(refspec.src));
|
2024-08-01 10:40:12 +00:00
|
|
|
free(refspec.src);
|
|
|
|
}
|
2009-02-25 08:32:22 +00:00
|
|
|
|
|
|
|
return 0;
|
2008-02-29 01:45:45 +00:00
|
|
|
}
|
|
|
|
|
2008-06-10 14:51:21 +00:00
|
|
|
static int get_remote_ref_states(const char *name,
|
|
|
|
struct ref_states *states,
|
|
|
|
int query)
|
|
|
|
{
|
|
|
|
states->remote = remote_get(name);
|
|
|
|
if (!states->remote)
|
2018-09-13 13:18:33 +00:00
|
|
|
return error(_("No such remote: '%s'"), name);
|
2008-06-10 14:51:21 +00:00
|
|
|
|
|
|
|
read_branches();
|
|
|
|
|
|
|
|
if (query) {
|
2021-03-21 16:58:37 +00:00
|
|
|
struct transport *transport;
|
|
|
|
const struct ref *remote_refs;
|
|
|
|
|
2024-06-14 10:42:03 +00:00
|
|
|
transport = transport_get(states->remote, states->remote->url.v[0]);
|
2018-03-15 17:31:23 +00:00
|
|
|
remote_refs = transport_get_remote_refs(transport, NULL);
|
2008-06-10 14:51:21 +00:00
|
|
|
|
2009-02-25 08:32:27 +00:00
|
|
|
states->queried = 1;
|
2009-02-25 08:32:24 +00:00
|
|
|
if (query & GET_REF_STATES)
|
|
|
|
get_ref_states(remote_refs, states);
|
|
|
|
if (query & GET_HEAD_NAMES)
|
|
|
|
get_head_names(remote_refs, states);
|
2009-02-25 08:32:28 +00:00
|
|
|
if (query & GET_PUSH_REF_STATES)
|
|
|
|
get_push_ref_states(remote_refs, states);
|
2021-03-21 16:58:37 +00:00
|
|
|
transport_disconnect(transport);
|
2009-02-25 08:32:23 +00:00
|
|
|
} else {
|
2024-05-07 07:11:53 +00:00
|
|
|
refs_for_each_ref(get_main_ref_store(the_repository),
|
|
|
|
append_ref_to_tracked_list, states);
|
2014-11-25 08:02:35 +00:00
|
|
|
string_list_sort(&states->tracked);
|
2009-02-25 08:32:28 +00:00
|
|
|
get_push_ref_states_noquery(states);
|
2008-06-10 14:51:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-02-25 08:32:27 +00:00
|
|
|
struct show_info {
|
2021-10-01 10:27:35 +00:00
|
|
|
struct string_list list;
|
|
|
|
struct ref_states states;
|
2009-02-25 08:32:28 +00:00
|
|
|
int width, width2;
|
2009-02-25 08:32:27 +00:00
|
|
|
int any_rebase;
|
|
|
|
};
|
|
|
|
|
2021-10-01 10:27:35 +00:00
|
|
|
#define SHOW_INFO_INIT { \
|
|
|
|
.list = STRING_LIST_INIT_DUP, \
|
|
|
|
.states = REF_STATES_INIT, \
|
|
|
|
}
|
|
|
|
|
2009-06-18 17:28:43 +00:00
|
|
|
static int add_remote_to_show_info(struct string_list_item *item, void *cb_data)
|
2008-06-10 22:54:49 +00:00
|
|
|
{
|
2009-02-25 08:32:27 +00:00
|
|
|
struct show_info *info = cb_data;
|
|
|
|
int n = strlen(item->string);
|
|
|
|
if (n > info->width)
|
|
|
|
info->width = n;
|
2021-10-01 10:27:35 +00:00
|
|
|
string_list_insert(&info->list, item->string);
|
2009-02-25 08:32:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2008-06-10 22:54:49 +00:00
|
|
|
|
2009-06-18 17:28:43 +00:00
|
|
|
static int show_remote_info_item(struct string_list_item *item, void *cb_data)
|
2009-02-25 08:32:27 +00:00
|
|
|
{
|
|
|
|
struct show_info *info = cb_data;
|
2021-10-01 10:27:35 +00:00
|
|
|
struct ref_states *states = &info->states;
|
2009-02-25 08:32:27 +00:00
|
|
|
const char *name = item->string;
|
|
|
|
|
|
|
|
if (states->queried) {
|
|
|
|
const char *fmt = "%s";
|
|
|
|
const char *arg = "";
|
2018-02-14 18:59:35 +00:00
|
|
|
if (string_list_has_string(&states->new_refs, name)) {
|
2012-04-23 12:30:26 +00:00
|
|
|
fmt = _(" new (next fetch will store in remotes/%s)");
|
2009-02-25 08:32:27 +00:00
|
|
|
arg = states->remote->name;
|
|
|
|
} else if (string_list_has_string(&states->tracked, name))
|
2012-04-23 12:30:26 +00:00
|
|
|
arg = _(" tracked");
|
2022-06-17 00:20:31 +00:00
|
|
|
else if (string_list_has_string(&states->skipped, name))
|
|
|
|
arg = _(" skipped");
|
2009-02-25 08:32:27 +00:00
|
|
|
else if (string_list_has_string(&states->stale, name))
|
2012-04-23 12:30:26 +00:00
|
|
|
arg = _(" stale (use 'git remote prune' to remove)");
|
2009-02-25 08:32:27 +00:00
|
|
|
else
|
2012-04-23 12:30:26 +00:00
|
|
|
arg = _(" ???");
|
2009-02-25 08:32:27 +00:00
|
|
|
printf(" %-*s", info->width, name);
|
|
|
|
printf(fmt, arg);
|
|
|
|
printf("\n");
|
|
|
|
} else
|
|
|
|
printf(" %s\n", name);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-06-18 17:28:43 +00:00
|
|
|
static int add_local_to_show_info(struct string_list_item *branch_item, void *cb_data)
|
2009-02-25 08:32:27 +00:00
|
|
|
{
|
|
|
|
struct show_info *show_info = cb_data;
|
2021-10-01 10:27:35 +00:00
|
|
|
struct ref_states *states = &show_info->states;
|
2009-02-25 08:32:27 +00:00
|
|
|
struct branch_info *branch_info = branch_item->util;
|
|
|
|
struct string_list_item *item;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
if (!branch_info->merge.nr || !branch_info->remote_name ||
|
|
|
|
strcmp(states->remote->name, branch_info->remote_name))
|
|
|
|
return 0;
|
|
|
|
if ((n = strlen(branch_item->string)) > show_info->width)
|
|
|
|
show_info->width = n;
|
2020-01-27 07:04:27 +00:00
|
|
|
if (branch_info->rebase >= REBASE_TRUE)
|
2009-02-25 08:32:27 +00:00
|
|
|
show_info->any_rebase = 1;
|
|
|
|
|
2021-10-01 10:27:35 +00:00
|
|
|
item = string_list_insert(&show_info->list, branch_item->string);
|
2009-02-25 08:32:27 +00:00
|
|
|
item->util = branch_info;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-06-18 17:28:43 +00:00
|
|
|
static int show_local_info_item(struct string_list_item *item, void *cb_data)
|
2009-02-25 08:32:27 +00:00
|
|
|
{
|
|
|
|
struct show_info *show_info = cb_data;
|
|
|
|
struct branch_info *branch_info = item->util;
|
|
|
|
struct string_list *merge = &branch_info->merge;
|
2016-06-17 20:21:22 +00:00
|
|
|
int width = show_info->width + 4;
|
2009-02-25 08:32:27 +00:00
|
|
|
int i;
|
|
|
|
|
2020-01-27 07:04:27 +00:00
|
|
|
if (branch_info->rebase >= REBASE_TRUE && branch_info->merge.nr > 1) {
|
2012-04-23 12:30:26 +00:00
|
|
|
error(_("invalid branch.%s.merge; cannot rebase onto > 1 branch"),
|
2009-02-25 08:32:27 +00:00
|
|
|
item->string);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf(" %-*s ", show_info->width, item->string);
|
2020-01-27 07:04:27 +00:00
|
|
|
if (branch_info->rebase >= REBASE_TRUE) {
|
2018-04-25 12:29:38 +00:00
|
|
|
const char *msg;
|
2020-01-27 07:04:27 +00:00
|
|
|
if (branch_info->rebase == REBASE_INTERACTIVE)
|
2018-04-25 12:29:38 +00:00
|
|
|
msg = _("rebases interactively onto remote %s");
|
|
|
|
else if (branch_info->rebase == REBASE_MERGES)
|
|
|
|
msg = _("rebases interactively (with merges) onto "
|
|
|
|
"remote %s");
|
|
|
|
else
|
|
|
|
msg = _("rebases onto remote %s");
|
|
|
|
printf_ln(msg, merge->items[0].string);
|
2009-02-25 08:32:27 +00:00
|
|
|
return 0;
|
|
|
|
} else if (show_info->any_rebase) {
|
2012-04-23 12:30:26 +00:00
|
|
|
printf_ln(_(" merges with remote %s"), merge->items[0].string);
|
2016-06-17 20:21:22 +00:00
|
|
|
width++;
|
2009-02-25 08:32:27 +00:00
|
|
|
} else {
|
2012-04-23 12:30:26 +00:00
|
|
|
printf_ln(_("merges with remote %s"), merge->items[0].string);
|
2009-02-25 08:32:27 +00:00
|
|
|
}
|
|
|
|
for (i = 1; i < merge->nr; i++)
|
2016-06-17 20:21:22 +00:00
|
|
|
printf(_("%-*s and with remote %s\n"), width, "",
|
2009-02-25 08:32:27 +00:00
|
|
|
merge->items[i].string);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2008-06-10 22:54:49 +00:00
|
|
|
|
2009-06-18 17:28:43 +00:00
|
|
|
static int add_push_to_show_info(struct string_list_item *push_item, void *cb_data)
|
2009-02-25 08:32:28 +00:00
|
|
|
{
|
|
|
|
struct show_info *show_info = cb_data;
|
|
|
|
struct push_info *push_info = push_item->util;
|
|
|
|
struct string_list_item *item;
|
|
|
|
int n;
|
|
|
|
if ((n = strlen(push_item->string)) > show_info->width)
|
|
|
|
show_info->width = n;
|
|
|
|
if ((n = strlen(push_info->dest)) > show_info->width2)
|
|
|
|
show_info->width2 = n;
|
2021-10-01 10:27:35 +00:00
|
|
|
item = string_list_append(&show_info->list, push_item->string);
|
2009-02-25 08:32:28 +00:00
|
|
|
item->util = push_item->util;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-22 08:59:20 +00:00
|
|
|
/*
|
|
|
|
* Sorting comparison for a string list that has push_info
|
|
|
|
* structs in its util field
|
|
|
|
*/
|
|
|
|
static int cmp_string_with_push(const void *va, const void *vb)
|
|
|
|
{
|
|
|
|
const struct string_list_item *a = va;
|
|
|
|
const struct string_list_item *b = vb;
|
|
|
|
const struct push_info *a_push = a->util;
|
|
|
|
const struct push_info *b_push = b->util;
|
|
|
|
int cmp = strcmp(a->string, b->string);
|
|
|
|
return cmp ? cmp : strcmp(a_push->dest, b_push->dest);
|
|
|
|
}
|
|
|
|
|
2009-06-18 17:28:43 +00:00
|
|
|
static int show_push_info_item(struct string_list_item *item, void *cb_data)
|
2009-02-25 08:32:28 +00:00
|
|
|
{
|
|
|
|
struct show_info *show_info = cb_data;
|
|
|
|
struct push_info *push_info = item->util;
|
2012-04-23 12:30:26 +00:00
|
|
|
const char *src = item->string, *status = NULL;
|
2009-02-25 08:32:28 +00:00
|
|
|
|
|
|
|
switch (push_info->status) {
|
|
|
|
case PUSH_STATUS_CREATE:
|
2012-04-23 12:30:26 +00:00
|
|
|
status = _("create");
|
2009-02-25 08:32:28 +00:00
|
|
|
break;
|
|
|
|
case PUSH_STATUS_DELETE:
|
2012-04-23 12:30:26 +00:00
|
|
|
status = _("delete");
|
|
|
|
src = _("(none)");
|
2009-02-25 08:32:28 +00:00
|
|
|
break;
|
|
|
|
case PUSH_STATUS_UPTODATE:
|
2012-04-23 12:30:26 +00:00
|
|
|
status = _("up to date");
|
2009-02-25 08:32:28 +00:00
|
|
|
break;
|
|
|
|
case PUSH_STATUS_FASTFORWARD:
|
2012-04-23 12:30:26 +00:00
|
|
|
status = _("fast-forwardable");
|
2009-02-25 08:32:28 +00:00
|
|
|
break;
|
|
|
|
case PUSH_STATUS_OUTOFDATE:
|
2012-04-23 12:30:26 +00:00
|
|
|
status = _("local out of date");
|
2009-02-25 08:32:28 +00:00
|
|
|
break;
|
|
|
|
case PUSH_STATUS_NOTQUERIED:
|
|
|
|
break;
|
|
|
|
}
|
2012-04-23 12:30:26 +00:00
|
|
|
if (status) {
|
|
|
|
if (push_info->forced)
|
|
|
|
printf_ln(_(" %-*s forces to %-*s (%s)"), show_info->width, src,
|
|
|
|
show_info->width2, push_info->dest, status);
|
|
|
|
else
|
|
|
|
printf_ln(_(" %-*s pushes to %-*s (%s)"), show_info->width, src,
|
|
|
|
show_info->width2, push_info->dest, status);
|
|
|
|
} else {
|
|
|
|
if (push_info->forced)
|
|
|
|
printf_ln(_(" %-*s forces to %s"), show_info->width, src,
|
|
|
|
push_info->dest);
|
|
|
|
else
|
|
|
|
printf_ln(_(" %-*s pushes to %s"), show_info->width, src,
|
|
|
|
push_info->dest);
|
|
|
|
}
|
2008-06-10 22:54:49 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-30 05:33:02 +00:00
|
|
|
static int get_one_entry(struct remote *remote, void *priv)
|
|
|
|
{
|
|
|
|
struct string_list *list = priv;
|
2022-05-09 11:32:48 +00:00
|
|
|
struct strbuf remote_info_buf = STRBUF_INIT;
|
remote: simplify url/pushurl selection
When we want to know the push urls for a remote, there is some simple
logic:
- if the user configured any remote.*.pushurl keys, then those make
the complete set of push urls
- otherwise we push to all urls in remote.*.url
Many spots implement this with a level of indirection, assigning to a
local url/url_nr pair. But since both arrays are now strvecs, we can
just use a pointer to select the appropriate strvec, shortening the code
a bit.
Even though this is now a one-liner, since it is application logic that
is present in so many places, it's worth abstracting a helper function.
In fact, we already have such a function, but it's local to
builtin/push.c. So we'll just make it available everywhere via remote.h.
There are two spots to pay special attention to here:
1. in builtin/remote.c's get_url(), we are selecting first based on
push_mode and then falling back to "url" when we're in push_mode
but no pushurl is defined. The updated code makes that much more
clear, compared to the original which had an "else" fall-through.
2. likewise in that file's set_url(), we _only_ respect push_mode,
sine the point is that we are adding to pushurl in that case
(whether it is empty or not). And thus it does not use our helper
function.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-14 10:29:09 +00:00
|
|
|
struct strvec *url;
|
|
|
|
int i;
|
2013-10-30 05:33:02 +00:00
|
|
|
|
2024-06-14 10:28:01 +00:00
|
|
|
if (remote->url.nr > 0) {
|
2022-05-09 11:32:48 +00:00
|
|
|
struct strbuf promisor_config = STRBUF_INIT;
|
|
|
|
const char *partial_clone_filter = NULL;
|
|
|
|
|
|
|
|
strbuf_addf(&promisor_config, "remote.%s.partialclonefilter", remote->name);
|
2024-06-14 10:28:01 +00:00
|
|
|
strbuf_addf(&remote_info_buf, "%s (fetch)", remote->url.v[0]);
|
2022-05-09 11:32:48 +00:00
|
|
|
if (!git_config_get_string_tmp(promisor_config.buf, &partial_clone_filter))
|
|
|
|
strbuf_addf(&remote_info_buf, " [%s]", partial_clone_filter);
|
|
|
|
|
|
|
|
strbuf_release(&promisor_config);
|
2013-10-30 05:33:02 +00:00
|
|
|
string_list_append(list, remote->name)->util =
|
2022-05-09 11:32:48 +00:00
|
|
|
strbuf_detach(&remote_info_buf, NULL);
|
2013-10-30 05:33:02 +00:00
|
|
|
} else
|
|
|
|
string_list_append(list, remote->name)->util = NULL;
|
remote: simplify url/pushurl selection
When we want to know the push urls for a remote, there is some simple
logic:
- if the user configured any remote.*.pushurl keys, then those make
the complete set of push urls
- otherwise we push to all urls in remote.*.url
Many spots implement this with a level of indirection, assigning to a
local url/url_nr pair. But since both arrays are now strvecs, we can
just use a pointer to select the appropriate strvec, shortening the code
a bit.
Even though this is now a one-liner, since it is application logic that
is present in so many places, it's worth abstracting a helper function.
In fact, we already have such a function, but it's local to
builtin/push.c. So we'll just make it available everywhere via remote.h.
There are two spots to pay special attention to here:
1. in builtin/remote.c's get_url(), we are selecting first based on
push_mode and then falling back to "url" when we're in push_mode
but no pushurl is defined. The updated code makes that much more
clear, compared to the original which had an "else" fall-through.
2. likewise in that file's set_url(), we _only_ respect push_mode,
sine the point is that we are adding to pushurl in that case
(whether it is empty or not). And thus it does not use our helper
function.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-14 10:29:09 +00:00
|
|
|
url = push_url_of_remote(remote);
|
|
|
|
for (i = 0; i < url->nr; i++)
|
2013-10-30 05:33:02 +00:00
|
|
|
{
|
remote: simplify url/pushurl selection
When we want to know the push urls for a remote, there is some simple
logic:
- if the user configured any remote.*.pushurl keys, then those make
the complete set of push urls
- otherwise we push to all urls in remote.*.url
Many spots implement this with a level of indirection, assigning to a
local url/url_nr pair. But since both arrays are now strvecs, we can
just use a pointer to select the appropriate strvec, shortening the code
a bit.
Even though this is now a one-liner, since it is application logic that
is present in so many places, it's worth abstracting a helper function.
In fact, we already have such a function, but it's local to
builtin/push.c. So we'll just make it available everywhere via remote.h.
There are two spots to pay special attention to here:
1. in builtin/remote.c's get_url(), we are selecting first based on
push_mode and then falling back to "url" when we're in push_mode
but no pushurl is defined. The updated code makes that much more
clear, compared to the original which had an "else" fall-through.
2. likewise in that file's set_url(), we _only_ respect push_mode,
sine the point is that we are adding to pushurl in that case
(whether it is empty or not). And thus it does not use our helper
function.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-14 10:29:09 +00:00
|
|
|
strbuf_addf(&remote_info_buf, "%s (push)", url->v[i]);
|
2013-10-30 05:33:02 +00:00
|
|
|
string_list_append(list, remote->name)->util =
|
2022-05-09 11:32:48 +00:00
|
|
|
strbuf_detach(&remote_info_buf, NULL);
|
2013-10-30 05:33:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int show_all(void)
|
|
|
|
{
|
2022-07-21 01:02:15 +00:00
|
|
|
struct string_list list = STRING_LIST_INIT_DUP;
|
2013-10-30 05:33:02 +00:00
|
|
|
int result;
|
|
|
|
|
|
|
|
result = for_each_remote(get_one_entry, &list);
|
|
|
|
|
|
|
|
if (!result) {
|
|
|
|
int i;
|
|
|
|
|
2014-11-25 08:02:35 +00:00
|
|
|
string_list_sort(&list);
|
2013-10-30 05:33:02 +00:00
|
|
|
for (i = 0; i < list.nr; i++) {
|
|
|
|
struct string_list_item *item = list.items + i;
|
|
|
|
if (verbose)
|
|
|
|
printf("%s\t%s\n", item->string,
|
|
|
|
item->util ? (const char *)item->util : "");
|
|
|
|
else {
|
|
|
|
if (i && !strcmp((item - 1)->string, item->string))
|
|
|
|
continue;
|
|
|
|
printf("%s\n", item->string);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
string_list_clear(&list, 1);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-08-19 16:04:08 +00:00
|
|
|
static int show(int argc, const char **argv, const char *prefix)
|
2008-02-29 01:45:45 +00:00
|
|
|
{
|
2009-02-25 08:32:24 +00:00
|
|
|
int no_query = 0, result = 0, query_flag = 0;
|
2008-02-29 01:45:45 +00:00
|
|
|
struct option options[] = {
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL('n', NULL, &no_query, N_("do not query remotes")),
|
2008-02-29 01:45:45 +00:00
|
|
|
OPT_END()
|
|
|
|
};
|
2021-10-01 10:27:35 +00:00
|
|
|
struct show_info info = SHOW_INFO_INIT;
|
2008-02-29 01:45:45 +00:00
|
|
|
|
pass subcommand "prefix" arguments to parse_options()
Recent commits such as bf0a6b65fc (builtin/multi-pack-index.c: let
parse-options parse subcommands, 2022-08-19) converted a few functions
to match our usual argc/argv/prefix conventions, but the prefix argument
remains unused.
However, there is a good use for it: they should pass it to their own
parse_options() functions, where it may be used to adjust the value of
any filename options. In all but one of these functions, there's no
behavior change, since they don't use OPT_FILENAME. But this is an
actual fix for one option, which you can see by modifying the test suite
like so:
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 4fe57414c1..d0974d4371 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -186,7 +186,11 @@ test_expect_success 'writing a bitmap with --refs-snapshot' '
# Then again, but with a refs snapshot which only sees
# refs/tags/one.
- git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
+ (
+ mkdir subdir &&
+ cd subdir &&
+ git multi-pack-index write --bitmap --refs-snapshot=../snapshot
+ ) &&
test_path_is_file $midx &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
I'd emphasize that this wasn't broken by bf0a6b65fc; it has been broken
all along, because the sub-function never got to see the prefix. It is
that commit which is actually enabling us to fix it (and which also
brought attention to the problem because it triggers -Wunused-parameter!)
The other functions changed here don't use OPT_FILENAME at all. In their
cases this isn't fixing anything visible, but it's following the usual
pattern and future-proofing them against somebody adding new options and
being surprised.
I didn't include a test for the one visible case above. We don't
generally test routine parse-options behavior for individual options.
The challenge here was finding the problem, and now that this has been
done, it's not likely to regress. Likewise, we could apply the patch
above to cover it "for free" but it makes reading the rest of the test
unnecessarily complicated.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-08-25 10:47:00 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, options,
|
|
|
|
builtin_remote_show_usage,
|
2009-05-23 18:53:12 +00:00
|
|
|
0);
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2008-06-10 14:51:21 +00:00
|
|
|
if (argc < 1)
|
|
|
|
return show_all();
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2009-02-25 08:32:24 +00:00
|
|
|
if (!no_query)
|
2009-02-25 08:32:28 +00:00
|
|
|
query_flag = (GET_REF_STATES | GET_HEAD_NAMES | GET_PUSH_REF_STATES);
|
2009-02-25 08:32:24 +00:00
|
|
|
|
2008-02-29 01:45:45 +00:00
|
|
|
for (; argc; argc--, argv++) {
|
2008-06-10 14:51:08 +00:00
|
|
|
int i;
|
remote: simplify url/pushurl selection
When we want to know the push urls for a remote, there is some simple
logic:
- if the user configured any remote.*.pushurl keys, then those make
the complete set of push urls
- otherwise we push to all urls in remote.*.url
Many spots implement this with a level of indirection, assigning to a
local url/url_nr pair. But since both arrays are now strvecs, we can
just use a pointer to select the appropriate strvec, shortening the code
a bit.
Even though this is now a one-liner, since it is application logic that
is present in so many places, it's worth abstracting a helper function.
In fact, we already have such a function, but it's local to
builtin/push.c. So we'll just make it available everywhere via remote.h.
There are two spots to pay special attention to here:
1. in builtin/remote.c's get_url(), we are selecting first based on
push_mode and then falling back to "url" when we're in push_mode
but no pushurl is defined. The updated code makes that much more
clear, compared to the original which had an "else" fall-through.
2. likewise in that file's set_url(), we _only_ respect push_mode,
sine the point is that we are adding to pushurl in that case
(whether it is empty or not). And thus it does not use our helper
function.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-14 10:29:09 +00:00
|
|
|
struct strvec *url;
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2021-10-01 10:27:35 +00:00
|
|
|
get_remote_ref_states(*argv, &info.states, query_flag);
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2012-04-23 12:30:26 +00:00
|
|
|
printf_ln(_("* remote %s"), *argv);
|
2024-06-14 10:42:03 +00:00
|
|
|
printf_ln(_(" Fetch URL: %s"), info.states.remote->url.v[0]);
|
remote: simplify url/pushurl selection
When we want to know the push urls for a remote, there is some simple
logic:
- if the user configured any remote.*.pushurl keys, then those make
the complete set of push urls
- otherwise we push to all urls in remote.*.url
Many spots implement this with a level of indirection, assigning to a
local url/url_nr pair. But since both arrays are now strvecs, we can
just use a pointer to select the appropriate strvec, shortening the code
a bit.
Even though this is now a one-liner, since it is application logic that
is present in so many places, it's worth abstracting a helper function.
In fact, we already have such a function, but it's local to
builtin/push.c. So we'll just make it available everywhere via remote.h.
There are two spots to pay special attention to here:
1. in builtin/remote.c's get_url(), we are selecting first based on
push_mode and then falling back to "url" when we're in push_mode
but no pushurl is defined. The updated code makes that much more
clear, compared to the original which had an "else" fall-through.
2. likewise in that file's set_url(), we _only_ respect push_mode,
sine the point is that we are adding to pushurl in that case
(whether it is empty or not). And thus it does not use our helper
function.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-14 10:29:09 +00:00
|
|
|
url = push_url_of_remote(info.states.remote);
|
|
|
|
for (i = 0; i < url->nr; i++)
|
C style: use standard style for "TRANSLATORS" comments
Change all the "TRANSLATORS: [...]" comments in the C code to use the
regular Git coding style, and amend the style guide so that the
example there uses that style.
This custom style was necessary back in 2010 when the gettext support
was initially added, and was subsequently documented in commit
cbcfd4e3ea ("i18n: mention "TRANSLATORS:" marker in
Documentation/CodingGuidelines", 2014-04-18).
GNU xgettext hasn't had the parsing limitation that necessitated this
exception for almost 3 years. Since its 0.19 release on 2014-06-02
it's been able to recognize TRANSLATOR comments in the standard Git
comment syntax[1].
Usually we'd like to keep compatibility with software that's that
young, but in this case literally the only person who needs to be
using a gettext newer than 3 years old is Jiang Xin (the only person
who runs & commits "make pot" results), so I think in this case we can
make an exception.
This xgettext parsing feature was added after a thread on the Git
mailing list[2] which continued on the bug-gettext[3] list, but we
never subsequently changed our style & styleguide, do so.
There are already longstanding changes in git that use the standard
comment style & have their TRANSLATORS comments extracted properly
without getting the literal "*"'s mixed up in the text, as would
happen before xgettext 0.19.
Commit 7ff2683253 ("builtin-am: implement -i/--interactive",
2015-08-04) added one such comment, which in commit df0617bfa7 ("l10n:
git.pot: v2.6.0 round 1 (123 new, 41 removed)", 2015-09-05) got picked
up in the po/git.pot file with the right format, showing that Jiang
already runs a modern xgettext.
The xgettext parser does not handle the sort of non-standard comment
style that I'm amending here in sequencer.c, but that isn't standard
Git comment syntax anyway. With this change to sequencer.c & "make
pot" the comment in the pot file is now correct:
#. TRANSLATORS: %s will be "revert", "cherry-pick" or
-#. * "rebase -i".
+#. "rebase -i".
1. http://git.savannah.gnu.org/cgit/gettext.git/commit/?id=10af7fe6bd
2. <2ce9ec406501d112e032c8208417f8100bed04c6.1397712142.git.worldhello.net@gmail.com>
(https://public-inbox.org/git/2ce9ec406501d112e032c8208417f8100bed04c6.1397712142.git.worldhello.net@gmail.com/)
3. https://lists.gnu.org/archive/html/bug-gettext/2014-04/msg00016.html
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Acked-by: Jiang Xin <worldhello.net@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-05-11 21:20:12 +00:00
|
|
|
/*
|
|
|
|
* TRANSLATORS: the colon ':' should align
|
|
|
|
* with the one in " Fetch URL: %s"
|
|
|
|
* translation.
|
|
|
|
*/
|
remote: simplify url/pushurl selection
When we want to know the push urls for a remote, there is some simple
logic:
- if the user configured any remote.*.pushurl keys, then those make
the complete set of push urls
- otherwise we push to all urls in remote.*.url
Many spots implement this with a level of indirection, assigning to a
local url/url_nr pair. But since both arrays are now strvecs, we can
just use a pointer to select the appropriate strvec, shortening the code
a bit.
Even though this is now a one-liner, since it is application logic that
is present in so many places, it's worth abstracting a helper function.
In fact, we already have such a function, but it's local to
builtin/push.c. So we'll just make it available everywhere via remote.h.
There are two spots to pay special attention to here:
1. in builtin/remote.c's get_url(), we are selecting first based on
push_mode and then falling back to "url" when we're in push_mode
but no pushurl is defined. The updated code makes that much more
clear, compared to the original which had an "else" fall-through.
2. likewise in that file's set_url(), we _only_ respect push_mode,
sine the point is that we are adding to pushurl in that case
(whether it is empty or not). And thus it does not use our helper
function.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-14 10:29:09 +00:00
|
|
|
printf_ln(_(" Push URL: %s"), url->v[i]);
|
2009-06-13 16:29:10 +00:00
|
|
|
if (!i)
|
2016-06-17 20:21:21 +00:00
|
|
|
printf_ln(_(" Push URL: %s"), _("(no URL)"));
|
2009-02-25 08:32:24 +00:00
|
|
|
if (no_query)
|
2016-06-17 20:21:21 +00:00
|
|
|
printf_ln(_(" HEAD branch: %s"), _("(not queried)"));
|
2021-10-01 10:27:35 +00:00
|
|
|
else if (!info.states.heads.nr)
|
2016-06-17 20:21:21 +00:00
|
|
|
printf_ln(_(" HEAD branch: %s"), _("(unknown)"));
|
2021-10-01 10:27:35 +00:00
|
|
|
else if (info.states.heads.nr == 1)
|
|
|
|
printf_ln(_(" HEAD branch: %s"), info.states.heads.items[0].string);
|
2009-02-25 08:32:24 +00:00
|
|
|
else {
|
2012-04-23 12:30:26 +00:00
|
|
|
printf(_(" HEAD branch (remote HEAD is ambiguous,"
|
|
|
|
" may be one of the following):\n"));
|
2021-10-01 10:27:35 +00:00
|
|
|
for (i = 0; i < info.states.heads.nr; i++)
|
|
|
|
printf(" %s\n", info.states.heads.items[i].string);
|
2008-02-29 01:45:45 +00:00
|
|
|
}
|
|
|
|
|
2009-02-25 08:32:27 +00:00
|
|
|
/* remote branch info */
|
|
|
|
info.width = 0;
|
2021-10-01 10:27:35 +00:00
|
|
|
for_each_string_list(&info.states.new_refs, add_remote_to_show_info, &info);
|
2022-06-17 00:20:31 +00:00
|
|
|
for_each_string_list(&info.states.skipped, add_remote_to_show_info, &info);
|
2021-10-01 10:27:35 +00:00
|
|
|
for_each_string_list(&info.states.tracked, add_remote_to_show_info, &info);
|
|
|
|
for_each_string_list(&info.states.stale, add_remote_to_show_info, &info);
|
|
|
|
if (info.list.nr)
|
2012-04-23 12:30:26 +00:00
|
|
|
printf_ln(Q_(" Remote branch:%s",
|
|
|
|
" Remote branches:%s",
|
2021-10-01 10:27:35 +00:00
|
|
|
info.list.nr),
|
2012-04-23 12:30:26 +00:00
|
|
|
no_query ? _(" (status not queried)") : "");
|
2021-10-01 10:27:35 +00:00
|
|
|
for_each_string_list(&info.list, show_remote_info_item, &info);
|
|
|
|
string_list_clear(&info.list, 0);
|
2009-02-25 08:32:27 +00:00
|
|
|
|
|
|
|
/* git pull info */
|
|
|
|
info.width = 0;
|
|
|
|
info.any_rebase = 0;
|
2010-06-25 23:41:34 +00:00
|
|
|
for_each_string_list(&branch_list, add_local_to_show_info, &info);
|
2021-10-01 10:27:35 +00:00
|
|
|
if (info.list.nr)
|
2012-04-23 12:30:26 +00:00
|
|
|
printf_ln(Q_(" Local branch configured for 'git pull':",
|
|
|
|
" Local branches configured for 'git pull':",
|
2021-10-01 10:27:35 +00:00
|
|
|
info.list.nr));
|
|
|
|
for_each_string_list(&info.list, show_local_info_item, &info);
|
|
|
|
string_list_clear(&info.list, 0);
|
2009-02-25 08:32:27 +00:00
|
|
|
|
|
|
|
/* git push info */
|
2021-10-01 10:27:35 +00:00
|
|
|
if (info.states.remote->mirror)
|
2012-04-23 12:30:26 +00:00
|
|
|
printf_ln(_(" Local refs will be mirrored by 'git push'"));
|
2009-02-25 08:32:28 +00:00
|
|
|
|
|
|
|
info.width = info.width2 = 0;
|
2021-10-01 10:27:35 +00:00
|
|
|
for_each_string_list(&info.states.push, add_push_to_show_info, &info);
|
|
|
|
QSORT(info.list.items, info.list.nr, cmp_string_with_push);
|
|
|
|
if (info.list.nr)
|
2012-04-23 12:30:26 +00:00
|
|
|
printf_ln(Q_(" Local ref configured for 'git push'%s:",
|
|
|
|
" Local refs configured for 'git push'%s:",
|
2021-10-01 10:27:35 +00:00
|
|
|
info.list.nr),
|
2012-04-23 12:30:26 +00:00
|
|
|
no_query ? _(" (status not queried)") : "");
|
2021-10-01 10:27:35 +00:00
|
|
|
for_each_string_list(&info.list, show_push_info_item, &info);
|
|
|
|
string_list_clear(&info.list, 0);
|
2008-06-10 14:51:21 +00:00
|
|
|
|
2021-10-01 10:27:35 +00:00
|
|
|
free_remote_ref_states(&info.states);
|
2008-06-10 14:51:21 +00:00
|
|
|
}
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2008-06-10 14:51:21 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-08-19 16:04:08 +00:00
|
|
|
static int set_head(int argc, const char **argv, const char *prefix)
|
2009-02-25 08:32:25 +00:00
|
|
|
{
|
|
|
|
int i, opt_a = 0, opt_d = 0, result = 0;
|
|
|
|
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
|
|
|
|
char *head_name = NULL;
|
|
|
|
|
|
|
|
struct option options[] = {
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL('a', "auto", &opt_a,
|
|
|
|
N_("set refs/remotes/<name>/HEAD according to remote")),
|
|
|
|
OPT_BOOL('d', "delete", &opt_d,
|
|
|
|
N_("delete refs/remotes/<name>/HEAD")),
|
2009-02-25 08:32:25 +00:00
|
|
|
OPT_END()
|
|
|
|
};
|
pass subcommand "prefix" arguments to parse_options()
Recent commits such as bf0a6b65fc (builtin/multi-pack-index.c: let
parse-options parse subcommands, 2022-08-19) converted a few functions
to match our usual argc/argv/prefix conventions, but the prefix argument
remains unused.
However, there is a good use for it: they should pass it to their own
parse_options() functions, where it may be used to adjust the value of
any filename options. In all but one of these functions, there's no
behavior change, since they don't use OPT_FILENAME. But this is an
actual fix for one option, which you can see by modifying the test suite
like so:
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 4fe57414c1..d0974d4371 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -186,7 +186,11 @@ test_expect_success 'writing a bitmap with --refs-snapshot' '
# Then again, but with a refs snapshot which only sees
# refs/tags/one.
- git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
+ (
+ mkdir subdir &&
+ cd subdir &&
+ git multi-pack-index write --bitmap --refs-snapshot=../snapshot
+ ) &&
test_path_is_file $midx &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
I'd emphasize that this wasn't broken by bf0a6b65fc; it has been broken
all along, because the sub-function never got to see the prefix. It is
that commit which is actually enabling us to fix it (and which also
brought attention to the problem because it triggers -Wunused-parameter!)
The other functions changed here don't use OPT_FILENAME at all. In their
cases this isn't fixing anything visible, but it's following the usual
pattern and future-proofing them against somebody adding new options and
being surprised.
I didn't include a test for the one visible case above. We don't
generally test routine parse-options behavior for individual options.
The challenge here was finding the problem, and now that this has been
done, it's not likely to regress. Likewise, we could apply the patch
above to cover it "for free" but it makes reading the rest of the test
unnecessarily complicated.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-08-25 10:47:00 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, options,
|
|
|
|
builtin_remote_sethead_usage, 0);
|
2009-02-25 08:32:25 +00:00
|
|
|
if (argc)
|
|
|
|
strbuf_addf(&buf, "refs/remotes/%s/HEAD", argv[0]);
|
|
|
|
|
|
|
|
if (!opt_a && !opt_d && argc == 2) {
|
|
|
|
head_name = xstrdup(argv[1]);
|
|
|
|
} else if (opt_a && !opt_d && argc == 1) {
|
builtin/remote.c: add and use a REF_STATES_INIT
Use a new REF_STATES_INIT designated initializer instead of assigning
to the "strdup_strings" member of the previously memzero()'d version
of this struct.
The pattern of assigning to "strdup_strings" dates back to
211c89682ee (Make git-remote a builtin, 2008-02-29) (when it was
"strdup_paths"), i.e. long before we used anything like our current
established *_INIT patterns consistently.
Then in e61e0cc6b70 (builtin-remote: teach show to display remote
HEAD, 2009-02-25) and e5dcbfd9ab7 (builtin-remote: new show output
style for push refspecs, 2009-02-25) we added some more of these.
As it turns out we only initialized this struct three times, all the
other uses were of pointers to those initialized structs. So let's
initialize it in those three places, skip the memset(), and pass those
structs down appropriately.
This would be a behavior change if we had codepaths that relied say on
implicitly having had "new_refs" initialized to STRING_LIST_INIT_NODUP
with the memset(), but only set the "strdup_strings" on some other
struct, but then called string_list_append() on "new_refs". There
isn't any such codepath, all of the late assignments to
"strdup_strings" assigned to those structs that we'd use for those
codepaths.
So just initializing them all up-front makes for easier to understand
code, i.e. in the pre-image it looked as though we had that tricky
edge case, but we didn't.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-10-01 10:27:34 +00:00
|
|
|
struct ref_states states = REF_STATES_INIT;
|
2009-02-25 08:32:25 +00:00
|
|
|
get_remote_ref_states(argv[0], &states, GET_HEAD_NAMES);
|
|
|
|
if (!states.heads.nr)
|
2012-04-23 12:30:26 +00:00
|
|
|
result |= error(_("Cannot determine remote HEAD"));
|
2009-02-25 08:32:25 +00:00
|
|
|
else if (states.heads.nr > 1) {
|
2012-04-23 12:30:26 +00:00
|
|
|
result |= error(_("Multiple remote HEAD branches. "
|
|
|
|
"Please choose one explicitly with:"));
|
2009-02-25 08:32:25 +00:00
|
|
|
for (i = 0; i < states.heads.nr; i++)
|
|
|
|
fprintf(stderr, " git remote set-head %s %s\n",
|
|
|
|
argv[0], states.heads.items[i].string);
|
|
|
|
} else
|
|
|
|
head_name = xstrdup(states.heads.items[0].string);
|
|
|
|
free_remote_ref_states(&states);
|
|
|
|
} else if (opt_d && !opt_a && argc == 1) {
|
2024-05-07 07:11:53 +00:00
|
|
|
if (refs_delete_ref(get_main_ref_store(the_repository), NULL, buf.buf, NULL, REF_NO_DEREF))
|
2012-04-23 12:30:26 +00:00
|
|
|
result |= error(_("Could not delete %s"), buf.buf);
|
2009-02-25 08:32:25 +00:00
|
|
|
} else
|
2009-11-20 23:43:13 +00:00
|
|
|
usage_with_options(builtin_remote_sethead_usage, options);
|
2009-02-25 08:32:25 +00:00
|
|
|
|
|
|
|
if (head_name) {
|
|
|
|
strbuf_addf(&buf2, "refs/remotes/%s/%s", argv[0], head_name);
|
|
|
|
/* make sure it's valid */
|
2024-05-07 07:11:53 +00:00
|
|
|
if (!refs_ref_exists(get_main_ref_store(the_repository), buf2.buf))
|
2012-04-23 12:30:26 +00:00
|
|
|
result |= error(_("Not a valid ref: %s"), buf2.buf);
|
2024-05-20 18:20:04 +00:00
|
|
|
else if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote set-head"))
|
2012-04-23 12:30:26 +00:00
|
|
|
result |= error(_("Could not setup %s"), buf.buf);
|
2020-09-17 15:27:38 +00:00
|
|
|
else if (opt_a)
|
2009-02-25 08:32:25 +00:00
|
|
|
printf("%s/HEAD set to %s\n", argv[0], head_name);
|
|
|
|
free(head_name);
|
2008-06-10 14:51:21 +00:00
|
|
|
}
|
|
|
|
|
2009-02-25 08:32:25 +00:00
|
|
|
strbuf_release(&buf);
|
|
|
|
strbuf_release(&buf2);
|
2008-06-10 14:51:21 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2009-04-03 09:02:37 +00:00
|
|
|
static int prune_remote(const char *remote, int dry_run)
|
|
|
|
{
|
2014-11-25 08:02:34 +00:00
|
|
|
int result = 0;
|
builtin/remote.c: add and use a REF_STATES_INIT
Use a new REF_STATES_INIT designated initializer instead of assigning
to the "strdup_strings" member of the previously memzero()'d version
of this struct.
The pattern of assigning to "strdup_strings" dates back to
211c89682ee (Make git-remote a builtin, 2008-02-29) (when it was
"strdup_paths"), i.e. long before we used anything like our current
established *_INIT patterns consistently.
Then in e61e0cc6b70 (builtin-remote: teach show to display remote
HEAD, 2009-02-25) and e5dcbfd9ab7 (builtin-remote: new show output
style for push refspecs, 2009-02-25) we added some more of these.
As it turns out we only initialized this struct three times, all the
other uses were of pointers to those initialized structs. So let's
initialize it in those three places, skip the memset(), and pass those
structs down appropriately.
This would be a behavior change if we had codepaths that relied say on
implicitly having had "new_refs" initialized to STRING_LIST_INIT_NODUP
with the memset(), but only set the "strdup_strings" on some other
struct, but then called string_list_append() on "new_refs". There
isn't any such codepath, all of the late assignments to
"strdup_strings" assigned to those structs that we'd use for those
codepaths.
So just initializing them all up-front makes for easier to understand
code, i.e. in the pre-image it looked as though we had that tricky
edge case, but we didn't.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-10-01 10:27:34 +00:00
|
|
|
struct ref_states states = REF_STATES_INIT;
|
2014-11-25 08:02:33 +00:00
|
|
|
struct string_list refs_to_prune = STRING_LIST_INIT_NODUP;
|
2014-11-25 08:02:34 +00:00
|
|
|
struct string_list_item *item;
|
2009-04-03 09:02:37 +00:00
|
|
|
const char *dangling_msg = dry_run
|
2012-04-23 12:30:26 +00:00
|
|
|
? _(" %s will become dangling!")
|
|
|
|
: _(" %s has become dangling!");
|
2008-06-10 14:51:21 +00:00
|
|
|
|
2009-04-03 09:02:37 +00:00
|
|
|
get_remote_ref_states(remote, &states, GET_REF_STATES);
|
|
|
|
|
2014-11-25 08:02:29 +00:00
|
|
|
if (!states.stale.nr) {
|
|
|
|
free_remote_ref_states(&states);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf_ln(_("Pruning %s"), remote);
|
2024-06-14 10:42:03 +00:00
|
|
|
printf_ln(_("URL: %s"), states.remote->url.v[0]);
|
2014-11-25 08:02:29 +00:00
|
|
|
|
2014-11-25 08:02:34 +00:00
|
|
|
for_each_string_list_item(item, &states.stale)
|
|
|
|
string_list_append(&refs_to_prune, item->util);
|
2014-11-25 08:02:35 +00:00
|
|
|
string_list_sort(&refs_to_prune);
|
2014-11-25 08:02:30 +00:00
|
|
|
|
2015-06-22 14:02:58 +00:00
|
|
|
if (!dry_run)
|
2024-05-07 07:11:53 +00:00
|
|
|
result |= refs_delete_refs(get_main_ref_store(the_repository),
|
|
|
|
"remote: prune", &refs_to_prune, 0);
|
2008-06-10 14:51:35 +00:00
|
|
|
|
2014-11-25 08:02:34 +00:00
|
|
|
for_each_string_list_item(item, &states.stale) {
|
|
|
|
const char *refname = item->util;
|
2008-06-10 14:51:35 +00:00
|
|
|
|
2012-04-23 12:30:26 +00:00
|
|
|
if (dry_run)
|
|
|
|
printf_ln(_(" * [would prune] %s"),
|
|
|
|
abbrev_ref(refname, "refs/remotes/"));
|
|
|
|
else
|
|
|
|
printf_ln(_(" * [pruned] %s"),
|
|
|
|
abbrev_ref(refname, "refs/remotes/"));
|
2008-02-29 01:45:45 +00:00
|
|
|
}
|
|
|
|
|
2024-05-17 08:18:53 +00:00
|
|
|
refs_warn_dangling_symrefs(get_main_ref_store(the_repository),
|
|
|
|
stdout, dangling_msg, &refs_to_prune);
|
2014-05-23 10:30:25 +00:00
|
|
|
|
2014-11-25 08:02:33 +00:00
|
|
|
string_list_clear(&refs_to_prune, 0);
|
2009-04-03 09:02:37 +00:00
|
|
|
free_remote_ref_states(&states);
|
2008-02-29 01:45:45 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-08-19 16:04:08 +00:00
|
|
|
static int prune(int argc, const char **argv, const char *prefix)
|
2013-10-30 05:33:02 +00:00
|
|
|
{
|
|
|
|
int dry_run = 0, result = 0;
|
|
|
|
struct option options[] = {
|
|
|
|
OPT__DRY_RUN(&dry_run, N_("dry run")),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
pass subcommand "prefix" arguments to parse_options()
Recent commits such as bf0a6b65fc (builtin/multi-pack-index.c: let
parse-options parse subcommands, 2022-08-19) converted a few functions
to match our usual argc/argv/prefix conventions, but the prefix argument
remains unused.
However, there is a good use for it: they should pass it to their own
parse_options() functions, where it may be used to adjust the value of
any filename options. In all but one of these functions, there's no
behavior change, since they don't use OPT_FILENAME. But this is an
actual fix for one option, which you can see by modifying the test suite
like so:
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 4fe57414c1..d0974d4371 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -186,7 +186,11 @@ test_expect_success 'writing a bitmap with --refs-snapshot' '
# Then again, but with a refs snapshot which only sees
# refs/tags/one.
- git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
+ (
+ mkdir subdir &&
+ cd subdir &&
+ git multi-pack-index write --bitmap --refs-snapshot=../snapshot
+ ) &&
test_path_is_file $midx &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
I'd emphasize that this wasn't broken by bf0a6b65fc; it has been broken
all along, because the sub-function never got to see the prefix. It is
that commit which is actually enabling us to fix it (and which also
brought attention to the problem because it triggers -Wunused-parameter!)
The other functions changed here don't use OPT_FILENAME at all. In their
cases this isn't fixing anything visible, but it's following the usual
pattern and future-proofing them against somebody adding new options and
being surprised.
I didn't include a test for the one visible case above. We don't
generally test routine parse-options behavior for individual options.
The challenge here was finding the problem, and now that this has been
done, it's not likely to regress. Likewise, we could apply the patch
above to cover it "for free" but it makes reading the rest of the test
unnecessarily complicated.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-08-25 10:47:00 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, options,
|
|
|
|
builtin_remote_prune_usage, 0);
|
2013-10-30 05:33:02 +00:00
|
|
|
|
|
|
|
if (argc < 1)
|
|
|
|
usage_with_options(builtin_remote_prune_usage, options);
|
|
|
|
|
|
|
|
for (; argc; argc--, argv++)
|
|
|
|
result |= prune_remote(*argv, dry_run);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
config: add ctx arg to config_fn_t
Add a new "const struct config_context *ctx" arg to config_fn_t to hold
additional information about the config iteration operation.
config_context has a "struct key_value_info kvi" member that holds
metadata about the config source being read (e.g. what kind of config
source it is, the filename, etc). In this series, we're only interested
in .kvi, so we could have just used "struct key_value_info" as an arg,
but config_context makes it possible to add/adjust members in the future
without changing the config_fn_t signature. We could also consider other
ways of organizing the args (e.g. moving the config name and value into
config_context or key_value_info), but in my experiments, the
incremental benefit doesn't justify the added complexity (e.g. a
config_fn_t will sometimes invoke another config_fn_t but with a
different config value).
In subsequent commits, the .kvi member will replace the global "struct
config_reader" in config.c, making config iteration a global-free
operation. It requires much more work for the machinery to provide
meaningful values of .kvi, so for now, merely change the signature and
call sites, pass NULL as a placeholder value, and don't rely on the arg
in any meaningful way.
Most of the changes are performed by
contrib/coccinelle/config_fn_ctx.pending.cocci, which, for every
config_fn_t:
- Modifies the signature to accept "const struct config_context *ctx"
- Passes "ctx" to any inner config_fn_t, if needed
- Adds UNUSED attributes to "ctx", if needed
Most config_fn_t instances are easily identified by seeing if they are
called by the various config functions. Most of the remaining ones are
manually named in the .cocci patch. Manual cleanups are still needed,
but the majority of it is trivial; it's either adjusting config_fn_t
that the .cocci patch didn't catch, or adding forward declarations of
"struct config_context ctx" to make the signatures make sense.
The non-trivial changes are in cases where we are invoking a config_fn_t
outside of config machinery, and we now need to decide what value of
"ctx" to pass. These cases are:
- trace2/tr2_cfg.c:tr2_cfg_set_fl()
This is indirectly called by git_config_set() so that the trace2
machinery can notice the new config values and update its settings
using the tr2 config parsing function, i.e. tr2_cfg_cb().
- builtin/checkout.c:checkout_main()
This calls git_xmerge_config() as a shorthand for parsing a CLI arg.
This might be worth refactoring away in the future, since
git_xmerge_config() can call git_default_config(), which can do much
more than just parsing.
Handle them by creating a KVI_INIT macro that initializes "struct
key_value_info" to a reasonable default, and use that to construct the
"ctx" arg.
Signed-off-by: Glen Choo <chooglen@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-06-28 19:26:22 +00:00
|
|
|
static int get_remote_default(const char *key, const char *value UNUSED,
|
|
|
|
const struct config_context *ctx UNUSED,
|
|
|
|
void *priv)
|
2008-02-29 01:45:45 +00:00
|
|
|
{
|
2009-11-10 08:21:32 +00:00
|
|
|
if (strcmp(key, "remotes.default") == 0) {
|
|
|
|
int *found = priv;
|
|
|
|
*found = 1;
|
2008-03-04 11:23:53 +00:00
|
|
|
}
|
2008-02-29 01:45:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-19 16:04:08 +00:00
|
|
|
static int update(int argc, const char **argv, const char *prefix)
|
2008-02-29 01:45:45 +00:00
|
|
|
{
|
2013-10-30 05:33:04 +00:00
|
|
|
int i, prune = -1;
|
2009-04-03 09:03:44 +00:00
|
|
|
struct option options[] = {
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL('p', "prune", &prune,
|
|
|
|
N_("prune remotes after fetching")),
|
2009-04-03 09:03:44 +00:00
|
|
|
OPT_END()
|
|
|
|
};
|
2022-10-30 11:51:14 +00:00
|
|
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
2009-11-10 08:21:32 +00:00
|
|
|
int default_defined = 0;
|
2008-02-29 01:45:45 +00:00
|
|
|
|
pass subcommand "prefix" arguments to parse_options()
Recent commits such as bf0a6b65fc (builtin/multi-pack-index.c: let
parse-options parse subcommands, 2022-08-19) converted a few functions
to match our usual argc/argv/prefix conventions, but the prefix argument
remains unused.
However, there is a good use for it: they should pass it to their own
parse_options() functions, where it may be used to adjust the value of
any filename options. In all but one of these functions, there's no
behavior change, since they don't use OPT_FILENAME. But this is an
actual fix for one option, which you can see by modifying the test suite
like so:
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 4fe57414c1..d0974d4371 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -186,7 +186,11 @@ test_expect_success 'writing a bitmap with --refs-snapshot' '
# Then again, but with a refs snapshot which only sees
# refs/tags/one.
- git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
+ (
+ mkdir subdir &&
+ cd subdir &&
+ git multi-pack-index write --bitmap --refs-snapshot=../snapshot
+ ) &&
test_path_is_file $midx &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
I'd emphasize that this wasn't broken by bf0a6b65fc; it has been broken
all along, because the sub-function never got to see the prefix. It is
that commit which is actually enabling us to fix it (and which also
brought attention to the problem because it triggers -Wunused-parameter!)
The other functions changed here don't use OPT_FILENAME at all. In their
cases this isn't fixing anything visible, but it's following the usual
pattern and future-proofing them against somebody adding new options and
being surprised.
I didn't include a test for the one visible case above. We don't
generally test routine parse-options behavior for individual options.
The challenge here was finding the problem, and now that this has been
done, it's not likely to regress. Likewise, we could apply the patch
above to cover it "for free" but it makes reading the rest of the test
unnecessarily complicated.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-08-25 10:47:00 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, options,
|
|
|
|
builtin_remote_update_usage,
|
2009-04-03 09:03:44 +00:00
|
|
|
PARSE_OPT_KEEP_ARGV0);
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2022-10-30 11:51:14 +00:00
|
|
|
strvec_push(&cmd.args, "fetch");
|
2008-03-04 11:23:53 +00:00
|
|
|
|
2013-10-30 05:33:04 +00:00
|
|
|
if (prune != -1)
|
2022-10-30 11:51:14 +00:00
|
|
|
strvec_push(&cmd.args, prune ? "--prune" : "--no-prune");
|
2009-11-10 08:21:32 +00:00
|
|
|
if (verbose)
|
2022-10-30 11:51:14 +00:00
|
|
|
strvec_push(&cmd.args, "-v");
|
|
|
|
strvec_push(&cmd.args, "--multiple");
|
2009-12-31 09:43:17 +00:00
|
|
|
if (argc < 2)
|
2022-10-30 11:51:14 +00:00
|
|
|
strvec_push(&cmd.args, "default");
|
2009-12-31 09:43:17 +00:00
|
|
|
for (i = 1; i < argc; i++)
|
2022-10-30 11:51:14 +00:00
|
|
|
strvec_push(&cmd.args, argv[i]);
|
2008-03-04 11:23:53 +00:00
|
|
|
|
2022-10-30 11:51:14 +00:00
|
|
|
if (strcmp(cmd.args.v[cmd.args.nr-1], "default") == 0) {
|
2009-11-10 08:21:32 +00:00
|
|
|
git_config(get_remote_default, &default_defined);
|
2013-10-30 05:33:03 +00:00
|
|
|
if (!default_defined) {
|
2022-10-30 11:51:14 +00:00
|
|
|
strvec_pop(&cmd.args);
|
|
|
|
strvec_push(&cmd.args, "--all");
|
2013-10-30 05:33:03 +00:00
|
|
|
}
|
2009-04-03 09:03:44 +00:00
|
|
|
}
|
2008-03-04 11:23:53 +00:00
|
|
|
|
2022-10-30 11:51:14 +00:00
|
|
|
cmd.git_cmd = 1;
|
|
|
|
return run_command(&cmd);
|
2008-02-29 01:45:45 +00:00
|
|
|
}
|
|
|
|
|
2019-05-09 21:31:46 +00:00
|
|
|
static int remove_all_fetch_refspecs(const char *key)
|
2010-05-19 18:38:50 +00:00
|
|
|
{
|
2020-11-25 22:12:49 +00:00
|
|
|
return git_config_set_multivar_gently(key, NULL, NULL,
|
|
|
|
CONFIG_FLAGS_MULTI_REPLACE);
|
2010-05-19 18:38:50 +00:00
|
|
|
}
|
|
|
|
|
2016-02-22 11:23:29 +00:00
|
|
|
static void add_branches(struct remote *remote, const char **branches,
|
|
|
|
const char *key)
|
2010-05-19 18:38:50 +00:00
|
|
|
{
|
|
|
|
const char *remotename = remote->name;
|
|
|
|
int mirror = remote->mirror;
|
|
|
|
struct strbuf refspec = STRBUF_INIT;
|
|
|
|
|
|
|
|
for (; *branches; branches++)
|
2016-02-22 11:23:29 +00:00
|
|
|
add_branch(key, *branches, remotename, mirror, &refspec);
|
2010-05-19 18:38:50 +00:00
|
|
|
|
|
|
|
strbuf_release(&refspec);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int set_remote_branches(const char *remotename, const char **branches,
|
|
|
|
int add_mode)
|
|
|
|
{
|
|
|
|
struct strbuf key = STRBUF_INIT;
|
|
|
|
struct remote *remote;
|
|
|
|
|
|
|
|
strbuf_addf(&key, "remote.%s.fetch", remotename);
|
|
|
|
|
|
|
|
remote = remote_get(remotename);
|
2020-10-27 09:41:36 +00:00
|
|
|
if (!remote_is_configured(remote, 1)) {
|
|
|
|
error(_("No such remote '%s'"), remotename);
|
|
|
|
exit(2);
|
|
|
|
}
|
2010-05-19 18:38:50 +00:00
|
|
|
|
2019-05-09 21:31:46 +00:00
|
|
|
if (!add_mode && remove_all_fetch_refspecs(key.buf)) {
|
2010-05-19 18:38:50 +00:00
|
|
|
strbuf_release(&key);
|
|
|
|
return 1;
|
|
|
|
}
|
2016-02-22 11:23:29 +00:00
|
|
|
add_branches(remote, branches, key.buf);
|
2010-05-19 18:38:50 +00:00
|
|
|
|
|
|
|
strbuf_release(&key);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-19 16:04:08 +00:00
|
|
|
static int set_branches(int argc, const char **argv, const char *prefix)
|
2010-05-19 18:38:50 +00:00
|
|
|
{
|
|
|
|
int add_mode = 0;
|
|
|
|
struct option options[] = {
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL('\0', "add", &add_mode, N_("add branch")),
|
2010-05-19 18:38:50 +00:00
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
pass subcommand "prefix" arguments to parse_options()
Recent commits such as bf0a6b65fc (builtin/multi-pack-index.c: let
parse-options parse subcommands, 2022-08-19) converted a few functions
to match our usual argc/argv/prefix conventions, but the prefix argument
remains unused.
However, there is a good use for it: they should pass it to their own
parse_options() functions, where it may be used to adjust the value of
any filename options. In all but one of these functions, there's no
behavior change, since they don't use OPT_FILENAME. But this is an
actual fix for one option, which you can see by modifying the test suite
like so:
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 4fe57414c1..d0974d4371 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -186,7 +186,11 @@ test_expect_success 'writing a bitmap with --refs-snapshot' '
# Then again, but with a refs snapshot which only sees
# refs/tags/one.
- git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
+ (
+ mkdir subdir &&
+ cd subdir &&
+ git multi-pack-index write --bitmap --refs-snapshot=../snapshot
+ ) &&
test_path_is_file $midx &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
I'd emphasize that this wasn't broken by bf0a6b65fc; it has been broken
all along, because the sub-function never got to see the prefix. It is
that commit which is actually enabling us to fix it (and which also
brought attention to the problem because it triggers -Wunused-parameter!)
The other functions changed here don't use OPT_FILENAME at all. In their
cases this isn't fixing anything visible, but it's following the usual
pattern and future-proofing them against somebody adding new options and
being surprised.
I didn't include a test for the one visible case above. We don't
generally test routine parse-options behavior for individual options.
The challenge here was finding the problem, and now that this has been
done, it's not likely to regress. Likewise, we could apply the patch
above to cover it "for free" but it makes reading the rest of the test
unnecessarily complicated.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-08-25 10:47:00 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, options,
|
2010-05-19 18:38:50 +00:00
|
|
|
builtin_remote_setbranches_usage, 0);
|
|
|
|
if (argc == 0) {
|
2012-04-23 12:30:26 +00:00
|
|
|
error(_("no remote specified"));
|
2011-11-07 05:12:59 +00:00
|
|
|
usage_with_options(builtin_remote_setbranches_usage, options);
|
2010-05-19 18:38:50 +00:00
|
|
|
}
|
|
|
|
argv[argc] = NULL;
|
|
|
|
|
|
|
|
return set_remote_branches(argv[0], argv + 1, add_mode);
|
|
|
|
}
|
|
|
|
|
2022-08-19 16:04:08 +00:00
|
|
|
static int get_url(int argc, const char **argv, const char *prefix)
|
2015-09-16 01:53:47 +00:00
|
|
|
{
|
|
|
|
int i, push_mode = 0, all_mode = 0;
|
|
|
|
const char *remotename = NULL;
|
|
|
|
struct remote *remote;
|
remote: simplify url/pushurl selection
When we want to know the push urls for a remote, there is some simple
logic:
- if the user configured any remote.*.pushurl keys, then those make
the complete set of push urls
- otherwise we push to all urls in remote.*.url
Many spots implement this with a level of indirection, assigning to a
local url/url_nr pair. But since both arrays are now strvecs, we can
just use a pointer to select the appropriate strvec, shortening the code
a bit.
Even though this is now a one-liner, since it is application logic that
is present in so many places, it's worth abstracting a helper function.
In fact, we already have such a function, but it's local to
builtin/push.c. So we'll just make it available everywhere via remote.h.
There are two spots to pay special attention to here:
1. in builtin/remote.c's get_url(), we are selecting first based on
push_mode and then falling back to "url" when we're in push_mode
but no pushurl is defined. The updated code makes that much more
clear, compared to the original which had an "else" fall-through.
2. likewise in that file's set_url(), we _only_ respect push_mode,
sine the point is that we are adding to pushurl in that case
(whether it is empty or not). And thus it does not use our helper
function.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-14 10:29:09 +00:00
|
|
|
struct strvec *url;
|
2015-09-16 01:53:47 +00:00
|
|
|
struct option options[] = {
|
|
|
|
OPT_BOOL('\0', "push", &push_mode,
|
|
|
|
N_("query push URLs rather than fetch URLs")),
|
|
|
|
OPT_BOOL('\0', "all", &all_mode,
|
|
|
|
N_("return all URLs")),
|
|
|
|
OPT_END()
|
|
|
|
};
|
pass subcommand "prefix" arguments to parse_options()
Recent commits such as bf0a6b65fc (builtin/multi-pack-index.c: let
parse-options parse subcommands, 2022-08-19) converted a few functions
to match our usual argc/argv/prefix conventions, but the prefix argument
remains unused.
However, there is a good use for it: they should pass it to their own
parse_options() functions, where it may be used to adjust the value of
any filename options. In all but one of these functions, there's no
behavior change, since they don't use OPT_FILENAME. But this is an
actual fix for one option, which you can see by modifying the test suite
like so:
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 4fe57414c1..d0974d4371 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -186,7 +186,11 @@ test_expect_success 'writing a bitmap with --refs-snapshot' '
# Then again, but with a refs snapshot which only sees
# refs/tags/one.
- git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
+ (
+ mkdir subdir &&
+ cd subdir &&
+ git multi-pack-index write --bitmap --refs-snapshot=../snapshot
+ ) &&
test_path_is_file $midx &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
I'd emphasize that this wasn't broken by bf0a6b65fc; it has been broken
all along, because the sub-function never got to see the prefix. It is
that commit which is actually enabling us to fix it (and which also
brought attention to the problem because it triggers -Wunused-parameter!)
The other functions changed here don't use OPT_FILENAME at all. In their
cases this isn't fixing anything visible, but it's following the usual
pattern and future-proofing them against somebody adding new options and
being surprised.
I didn't include a test for the one visible case above. We don't
generally test routine parse-options behavior for individual options.
The challenge here was finding the problem, and now that this has been
done, it's not likely to regress. Likewise, we could apply the patch
above to cover it "for free" but it makes reading the rest of the test
unnecessarily complicated.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-08-25 10:47:00 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, options,
|
|
|
|
builtin_remote_geturl_usage, 0);
|
2015-09-16 01:53:47 +00:00
|
|
|
|
|
|
|
if (argc != 1)
|
|
|
|
usage_with_options(builtin_remote_geturl_usage, options);
|
|
|
|
|
|
|
|
remotename = argv[0];
|
|
|
|
|
|
|
|
remote = remote_get(remotename);
|
2020-10-27 09:41:36 +00:00
|
|
|
if (!remote_is_configured(remote, 1)) {
|
|
|
|
error(_("No such remote '%s'"), remotename);
|
|
|
|
exit(2);
|
|
|
|
}
|
2015-09-16 01:53:47 +00:00
|
|
|
|
remote: simplify url/pushurl selection
When we want to know the push urls for a remote, there is some simple
logic:
- if the user configured any remote.*.pushurl keys, then those make
the complete set of push urls
- otherwise we push to all urls in remote.*.url
Many spots implement this with a level of indirection, assigning to a
local url/url_nr pair. But since both arrays are now strvecs, we can
just use a pointer to select the appropriate strvec, shortening the code
a bit.
Even though this is now a one-liner, since it is application logic that
is present in so many places, it's worth abstracting a helper function.
In fact, we already have such a function, but it's local to
builtin/push.c. So we'll just make it available everywhere via remote.h.
There are two spots to pay special attention to here:
1. in builtin/remote.c's get_url(), we are selecting first based on
push_mode and then falling back to "url" when we're in push_mode
but no pushurl is defined. The updated code makes that much more
clear, compared to the original which had an "else" fall-through.
2. likewise in that file's set_url(), we _only_ respect push_mode,
sine the point is that we are adding to pushurl in that case
(whether it is empty or not). And thus it does not use our helper
function.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-14 10:29:09 +00:00
|
|
|
url = push_mode ? push_url_of_remote(remote) : &remote->url;
|
2015-09-16 01:53:47 +00:00
|
|
|
|
|
|
|
if (all_mode) {
|
remote: simplify url/pushurl selection
When we want to know the push urls for a remote, there is some simple
logic:
- if the user configured any remote.*.pushurl keys, then those make
the complete set of push urls
- otherwise we push to all urls in remote.*.url
Many spots implement this with a level of indirection, assigning to a
local url/url_nr pair. But since both arrays are now strvecs, we can
just use a pointer to select the appropriate strvec, shortening the code
a bit.
Even though this is now a one-liner, since it is application logic that
is present in so many places, it's worth abstracting a helper function.
In fact, we already have such a function, but it's local to
builtin/push.c. So we'll just make it available everywhere via remote.h.
There are two spots to pay special attention to here:
1. in builtin/remote.c's get_url(), we are selecting first based on
push_mode and then falling back to "url" when we're in push_mode
but no pushurl is defined. The updated code makes that much more
clear, compared to the original which had an "else" fall-through.
2. likewise in that file's set_url(), we _only_ respect push_mode,
sine the point is that we are adding to pushurl in that case
(whether it is empty or not). And thus it does not use our helper
function.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-14 10:29:09 +00:00
|
|
|
for (i = 0; i < url->nr; i++)
|
|
|
|
printf_ln("%s", url->v[i]);
|
2015-09-16 01:53:47 +00:00
|
|
|
} else {
|
remote: simplify url/pushurl selection
When we want to know the push urls for a remote, there is some simple
logic:
- if the user configured any remote.*.pushurl keys, then those make
the complete set of push urls
- otherwise we push to all urls in remote.*.url
Many spots implement this with a level of indirection, assigning to a
local url/url_nr pair. But since both arrays are now strvecs, we can
just use a pointer to select the appropriate strvec, shortening the code
a bit.
Even though this is now a one-liner, since it is application logic that
is present in so many places, it's worth abstracting a helper function.
In fact, we already have such a function, but it's local to
builtin/push.c. So we'll just make it available everywhere via remote.h.
There are two spots to pay special attention to here:
1. in builtin/remote.c's get_url(), we are selecting first based on
push_mode and then falling back to "url" when we're in push_mode
but no pushurl is defined. The updated code makes that much more
clear, compared to the original which had an "else" fall-through.
2. likewise in that file's set_url(), we _only_ respect push_mode,
sine the point is that we are adding to pushurl in that case
(whether it is empty or not). And thus it does not use our helper
function.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-14 10:29:09 +00:00
|
|
|
printf_ln("%s", url->v[0]);
|
2015-09-16 01:53:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-19 16:04:08 +00:00
|
|
|
static int set_url(int argc, const char **argv, const char *prefix)
|
2010-01-18 17:18:02 +00:00
|
|
|
{
|
|
|
|
int i, push_mode = 0, add_mode = 0, delete_mode = 0;
|
|
|
|
int matches = 0, negative_matches = 0;
|
|
|
|
const char *remotename = NULL;
|
|
|
|
const char *newurl = NULL;
|
|
|
|
const char *oldurl = NULL;
|
|
|
|
struct remote *remote;
|
|
|
|
regex_t old_regex;
|
remote: simplify url/pushurl selection
When we want to know the push urls for a remote, there is some simple
logic:
- if the user configured any remote.*.pushurl keys, then those make
the complete set of push urls
- otherwise we push to all urls in remote.*.url
Many spots implement this with a level of indirection, assigning to a
local url/url_nr pair. But since both arrays are now strvecs, we can
just use a pointer to select the appropriate strvec, shortening the code
a bit.
Even though this is now a one-liner, since it is application logic that
is present in so many places, it's worth abstracting a helper function.
In fact, we already have such a function, but it's local to
builtin/push.c. So we'll just make it available everywhere via remote.h.
There are two spots to pay special attention to here:
1. in builtin/remote.c's get_url(), we are selecting first based on
push_mode and then falling back to "url" when we're in push_mode
but no pushurl is defined. The updated code makes that much more
clear, compared to the original which had an "else" fall-through.
2. likewise in that file's set_url(), we _only_ respect push_mode,
sine the point is that we are adding to pushurl in that case
(whether it is empty or not). And thus it does not use our helper
function.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-14 10:29:09 +00:00
|
|
|
struct strvec *urlset;
|
2010-01-18 17:18:02 +00:00
|
|
|
struct strbuf name_buf = STRBUF_INIT;
|
|
|
|
struct option options[] = {
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL('\0', "push", &push_mode,
|
|
|
|
N_("manipulate push URLs")),
|
|
|
|
OPT_BOOL('\0', "add", &add_mode,
|
|
|
|
N_("add URL")),
|
|
|
|
OPT_BOOL('\0', "delete", &delete_mode,
|
2012-08-20 12:32:35 +00:00
|
|
|
N_("delete URLs")),
|
2010-01-18 17:18:02 +00:00
|
|
|
OPT_END()
|
|
|
|
};
|
pass subcommand "prefix" arguments to parse_options()
Recent commits such as bf0a6b65fc (builtin/multi-pack-index.c: let
parse-options parse subcommands, 2022-08-19) converted a few functions
to match our usual argc/argv/prefix conventions, but the prefix argument
remains unused.
However, there is a good use for it: they should pass it to their own
parse_options() functions, where it may be used to adjust the value of
any filename options. In all but one of these functions, there's no
behavior change, since they don't use OPT_FILENAME. But this is an
actual fix for one option, which you can see by modifying the test suite
like so:
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 4fe57414c1..d0974d4371 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -186,7 +186,11 @@ test_expect_success 'writing a bitmap with --refs-snapshot' '
# Then again, but with a refs snapshot which only sees
# refs/tags/one.
- git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
+ (
+ mkdir subdir &&
+ cd subdir &&
+ git multi-pack-index write --bitmap --refs-snapshot=../snapshot
+ ) &&
test_path_is_file $midx &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
I'd emphasize that this wasn't broken by bf0a6b65fc; it has been broken
all along, because the sub-function never got to see the prefix. It is
that commit which is actually enabling us to fix it (and which also
brought attention to the problem because it triggers -Wunused-parameter!)
The other functions changed here don't use OPT_FILENAME at all. In their
cases this isn't fixing anything visible, but it's following the usual
pattern and future-proofing them against somebody adding new options and
being surprised.
I didn't include a test for the one visible case above. We don't
generally test routine parse-options behavior for individual options.
The challenge here was finding the problem, and now that this has been
done, it's not likely to regress. Likewise, we could apply the patch
above to cover it "for free" but it makes reading the rest of the test
unnecessarily complicated.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-08-25 10:47:00 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, options,
|
|
|
|
builtin_remote_seturl_usage,
|
2010-01-18 17:18:02 +00:00
|
|
|
PARSE_OPT_KEEP_ARGV0);
|
|
|
|
|
|
|
|
if (add_mode && delete_mode)
|
2012-04-23 12:30:26 +00:00
|
|
|
die(_("--add --delete doesn't make sense"));
|
2010-01-18 17:18:02 +00:00
|
|
|
|
|
|
|
if (argc < 3 || argc > 4 || ((add_mode || delete_mode) && argc != 3))
|
|
|
|
usage_with_options(builtin_remote_seturl_usage, options);
|
|
|
|
|
|
|
|
remotename = argv[1];
|
|
|
|
newurl = argv[2];
|
|
|
|
if (argc > 3)
|
|
|
|
oldurl = argv[3];
|
|
|
|
|
|
|
|
if (delete_mode)
|
|
|
|
oldurl = newurl;
|
|
|
|
|
|
|
|
remote = remote_get(remotename);
|
2020-10-27 09:41:36 +00:00
|
|
|
if (!remote_is_configured(remote, 1)) {
|
|
|
|
error(_("No such remote '%s'"), remotename);
|
|
|
|
exit(2);
|
|
|
|
}
|
2010-01-18 17:18:02 +00:00
|
|
|
|
|
|
|
if (push_mode) {
|
|
|
|
strbuf_addf(&name_buf, "remote.%s.pushurl", remotename);
|
remote: simplify url/pushurl selection
When we want to know the push urls for a remote, there is some simple
logic:
- if the user configured any remote.*.pushurl keys, then those make
the complete set of push urls
- otherwise we push to all urls in remote.*.url
Many spots implement this with a level of indirection, assigning to a
local url/url_nr pair. But since both arrays are now strvecs, we can
just use a pointer to select the appropriate strvec, shortening the code
a bit.
Even though this is now a one-liner, since it is application logic that
is present in so many places, it's worth abstracting a helper function.
In fact, we already have such a function, but it's local to
builtin/push.c. So we'll just make it available everywhere via remote.h.
There are two spots to pay special attention to here:
1. in builtin/remote.c's get_url(), we are selecting first based on
push_mode and then falling back to "url" when we're in push_mode
but no pushurl is defined. The updated code makes that much more
clear, compared to the original which had an "else" fall-through.
2. likewise in that file's set_url(), we _only_ respect push_mode,
sine the point is that we are adding to pushurl in that case
(whether it is empty or not). And thus it does not use our helper
function.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-14 10:29:09 +00:00
|
|
|
urlset = &remote->pushurl;
|
2010-01-18 17:18:02 +00:00
|
|
|
} else {
|
|
|
|
strbuf_addf(&name_buf, "remote.%s.url", remotename);
|
remote: simplify url/pushurl selection
When we want to know the push urls for a remote, there is some simple
logic:
- if the user configured any remote.*.pushurl keys, then those make
the complete set of push urls
- otherwise we push to all urls in remote.*.url
Many spots implement this with a level of indirection, assigning to a
local url/url_nr pair. But since both arrays are now strvecs, we can
just use a pointer to select the appropriate strvec, shortening the code
a bit.
Even though this is now a one-liner, since it is application logic that
is present in so many places, it's worth abstracting a helper function.
In fact, we already have such a function, but it's local to
builtin/push.c. So we'll just make it available everywhere via remote.h.
There are two spots to pay special attention to here:
1. in builtin/remote.c's get_url(), we are selecting first based on
push_mode and then falling back to "url" when we're in push_mode
but no pushurl is defined. The updated code makes that much more
clear, compared to the original which had an "else" fall-through.
2. likewise in that file's set_url(), we _only_ respect push_mode,
sine the point is that we are adding to pushurl in that case
(whether it is empty or not). And thus it does not use our helper
function.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-14 10:29:09 +00:00
|
|
|
urlset = &remote->url;
|
2010-01-18 17:18:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Special cases that add new entry. */
|
|
|
|
if ((!oldurl && !delete_mode) || add_mode) {
|
|
|
|
if (add_mode)
|
|
|
|
git_config_set_multivar(name_buf.buf, newurl,
|
2016-02-22 11:23:28 +00:00
|
|
|
"^$", 0);
|
2010-01-18 17:18:02 +00:00
|
|
|
else
|
|
|
|
git_config_set(name_buf.buf, newurl);
|
2017-08-30 18:00:27 +00:00
|
|
|
goto out;
|
2010-01-18 17:18:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Old URL specified. Demand that one matches. */
|
|
|
|
if (regcomp(&old_regex, oldurl, REG_EXTENDED))
|
2012-04-23 12:30:26 +00:00
|
|
|
die(_("Invalid old URL pattern: %s"), oldurl);
|
2010-01-18 17:18:02 +00:00
|
|
|
|
remote: simplify url/pushurl selection
When we want to know the push urls for a remote, there is some simple
logic:
- if the user configured any remote.*.pushurl keys, then those make
the complete set of push urls
- otherwise we push to all urls in remote.*.url
Many spots implement this with a level of indirection, assigning to a
local url/url_nr pair. But since both arrays are now strvecs, we can
just use a pointer to select the appropriate strvec, shortening the code
a bit.
Even though this is now a one-liner, since it is application logic that
is present in so many places, it's worth abstracting a helper function.
In fact, we already have such a function, but it's local to
builtin/push.c. So we'll just make it available everywhere via remote.h.
There are two spots to pay special attention to here:
1. in builtin/remote.c's get_url(), we are selecting first based on
push_mode and then falling back to "url" when we're in push_mode
but no pushurl is defined. The updated code makes that much more
clear, compared to the original which had an "else" fall-through.
2. likewise in that file's set_url(), we _only_ respect push_mode,
sine the point is that we are adding to pushurl in that case
(whether it is empty or not). And thus it does not use our helper
function.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-14 10:29:09 +00:00
|
|
|
for (i = 0; i < urlset->nr; i++)
|
|
|
|
if (!regexec(&old_regex, urlset->v[i], 0, NULL, 0))
|
2010-01-18 17:18:02 +00:00
|
|
|
matches++;
|
|
|
|
else
|
|
|
|
negative_matches++;
|
|
|
|
if (!delete_mode && !matches)
|
2012-04-23 12:30:26 +00:00
|
|
|
die(_("No such URL found: %s"), oldurl);
|
2010-01-18 17:18:02 +00:00
|
|
|
if (delete_mode && !negative_matches && !push_mode)
|
2012-04-23 12:30:26 +00:00
|
|
|
die(_("Will not delete all non-push URLs"));
|
2010-01-18 17:18:02 +00:00
|
|
|
|
|
|
|
regfree(&old_regex);
|
|
|
|
|
|
|
|
if (!delete_mode)
|
|
|
|
git_config_set_multivar(name_buf.buf, newurl, oldurl, 0);
|
|
|
|
else
|
2020-11-25 22:12:49 +00:00
|
|
|
git_config_set_multivar(name_buf.buf, NULL, oldurl,
|
|
|
|
CONFIG_FLAGS_MULTI_REPLACE);
|
2017-08-30 18:00:27 +00:00
|
|
|
out:
|
|
|
|
strbuf_release(&name_buf);
|
2010-01-18 17:18:02 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-29 01:45:45 +00:00
|
|
|
int cmd_remote(int argc, const char **argv, const char *prefix)
|
|
|
|
{
|
2022-08-19 16:04:08 +00:00
|
|
|
parse_opt_subcommand_fn *fn = NULL;
|
2008-02-29 01:45:45 +00:00
|
|
|
struct option options[] = {
|
2012-08-20 12:32:35 +00:00
|
|
|
OPT__VERBOSE(&verbose, N_("be verbose; must be placed before a subcommand")),
|
2022-08-19 16:04:08 +00:00
|
|
|
OPT_SUBCOMMAND("add", &fn, add),
|
|
|
|
OPT_SUBCOMMAND("rename", &fn, mv),
|
|
|
|
OPT_SUBCOMMAND_F("rm", &fn, rm, PARSE_OPT_NOCOMPLETE),
|
|
|
|
OPT_SUBCOMMAND("remove", &fn, rm),
|
|
|
|
OPT_SUBCOMMAND("set-head", &fn, set_head),
|
|
|
|
OPT_SUBCOMMAND("set-branches", &fn, set_branches),
|
|
|
|
OPT_SUBCOMMAND("get-url", &fn, get_url),
|
|
|
|
OPT_SUBCOMMAND("set-url", &fn, set_url),
|
|
|
|
OPT_SUBCOMMAND("show", &fn, show),
|
|
|
|
OPT_SUBCOMMAND("prune", &fn, prune),
|
|
|
|
OPT_SUBCOMMAND("update", &fn, update),
|
2008-02-29 01:45:45 +00:00
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
2009-05-23 18:53:12 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, options, builtin_remote_usage,
|
2022-08-19 16:04:08 +00:00
|
|
|
PARSE_OPT_SUBCOMMAND_OPTIONAL);
|
2008-02-29 01:45:45 +00:00
|
|
|
|
2022-08-19 16:04:08 +00:00
|
|
|
if (fn) {
|
|
|
|
return !!fn(argc, argv, prefix);
|
|
|
|
} else {
|
|
|
|
if (argc) {
|
2022-09-05 18:50:07 +00:00
|
|
|
error(_("unknown subcommand: `%s'"), argv[0]);
|
2022-08-19 16:04:08 +00:00
|
|
|
usage_with_options(builtin_remote_usage, options);
|
|
|
|
}
|
|
|
|
return !!show_all();
|
2008-02-29 01:45:45 +00:00
|
|
|
}
|
|
|
|
}
|