2011-08-11 09:15:38 +00:00
|
|
|
#include "git-compat-util.h"
|
|
|
|
#include "parse-options.h"
|
branch: add flags and config to inherit tracking
It can be helpful when creating a new branch to use the existing
tracking configuration from the branch point. However, there is
currently not a method to automatically do so.
Teach git-{branch,checkout,switch} an "inherit" argument to the
"--track" option. When this is set, creating a new branch will cause the
tracking configuration to default to the configuration of the branch
point, if set.
For example, if branch "main" tracks "origin/main", and we run
`git checkout --track=inherit -b feature main`, then branch "feature"
will track "origin/main". Thus, `git status` will show us how far
ahead/behind we are from origin, and `git pull` will pull from origin.
This is particularly useful when creating branches across many
submodules, such as with `git submodule foreach ...` (or if running with
a patch such as [1], which we use at $job), as it avoids having to
manually set tracking info for each submodule.
Since we've added an argument to "--track", also add "--track=direct" as
another way to explicitly get the original "--track" behavior ("--track"
without an argument still works as well).
Finally, teach branch.autoSetupMerge a new "inherit" option. When this
is set, "--track=inherit" becomes the default behavior.
[1]: https://lore.kernel.org/git/20180927221603.148025-1-sbeller@google.com/
Signed-off-by: Josh Steadmon <steadmon@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-21 03:30:23 +00:00
|
|
|
#include "branch.h"
|
2011-08-11 09:15:38 +00:00
|
|
|
#include "commit.h"
|
|
|
|
#include "color.h"
|
2023-04-22 20:17:26 +00:00
|
|
|
#include "date.h"
|
2023-03-21 06:26:03 +00:00
|
|
|
#include "environment.h"
|
2023-03-21 06:25:54 +00:00
|
|
|
#include "gettext.h"
|
2023-04-11 07:41:49 +00:00
|
|
|
#include "object-name.h"
|
2011-08-11 09:15:38 +00:00
|
|
|
#include "string-list.h"
|
2020-07-28 20:23:39 +00:00
|
|
|
#include "strvec.h"
|
2020-03-30 14:03:46 +00:00
|
|
|
#include "oid-array.h"
|
2011-08-11 09:15:38 +00:00
|
|
|
|
|
|
|
/*----- some often used options -----*/
|
|
|
|
|
|
|
|
int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
int v;
|
|
|
|
|
|
|
|
if (!arg) {
|
|
|
|
v = unset ? 0 : DEFAULT_ABBREV;
|
|
|
|
} else {
|
2019-05-29 09:11:16 +00:00
|
|
|
if (!*arg)
|
|
|
|
return error(_("option `%s' expects a numerical value"),
|
|
|
|
opt->long_name);
|
2011-08-11 09:15:38 +00:00
|
|
|
v = strtol(arg, (char **)&arg, 10);
|
|
|
|
if (*arg)
|
2018-11-10 05:16:11 +00:00
|
|
|
return error(_("option `%s' expects a numerical value"),
|
|
|
|
opt->long_name);
|
2011-08-11 09:15:38 +00:00
|
|
|
if (v && v < MINIMUM_ABBREV)
|
|
|
|
v = MINIMUM_ABBREV;
|
2019-03-24 08:20:04 +00:00
|
|
|
else if (v > the_hash_algo->hexsz)
|
|
|
|
v = the_hash_algo->hexsz;
|
2011-08-11 09:15:38 +00:00
|
|
|
}
|
|
|
|
*(int *)(opt->value) = v;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-25 18:13:49 +00:00
|
|
|
int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,
|
|
|
|
int unset)
|
|
|
|
{
|
2018-04-21 03:13:13 +00:00
|
|
|
if (unset)
|
|
|
|
arg = "never";
|
|
|
|
if (parse_expiry_date(arg, (timestamp_t *)opt->value))
|
|
|
|
die(_("malformed expiration date '%s'"), arg);
|
|
|
|
return 0;
|
2013-04-25 18:13:49 +00:00
|
|
|
}
|
|
|
|
|
2011-08-11 09:15:38 +00:00
|
|
|
int parse_opt_color_flag_cb(const struct option *opt, const char *arg,
|
|
|
|
int unset)
|
|
|
|
{
|
|
|
|
int value;
|
|
|
|
|
|
|
|
if (!arg)
|
|
|
|
arg = unset ? "never" : (const char *)opt->defval;
|
2011-08-29 04:19:16 +00:00
|
|
|
value = git_config_colorbool(NULL, arg);
|
2011-08-11 09:15:38 +00:00
|
|
|
if (value < 0)
|
2018-11-10 05:16:11 +00:00
|
|
|
return error(_("option `%s' expects \"always\", \"auto\", or \"never\""),
|
|
|
|
opt->long_name);
|
2011-08-11 09:15:38 +00:00
|
|
|
*(int *)opt->value = value;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parse_opt_verbosity_cb(const struct option *opt, const char *arg,
|
|
|
|
int unset)
|
|
|
|
{
|
|
|
|
int *target = opt->value;
|
|
|
|
|
assert NOARG/NONEG behavior of parse-options callbacks
When we define a parse-options callback, the flags we put in the option
struct must match what the callback expects. For example, a callback
which does not handle the "unset" parameter should only be used with
PARSE_OPT_NONEG. But since the callback and the option struct are not
defined next to each other, it's easy to get this wrong (as earlier
patches in this series show).
Fortunately, the compiler can help us here: compiling with
-Wunused-parameters can show us which callbacks ignore their "unset"
parameters (and likewise, ones that ignore "arg" expect to be triggered
with PARSE_OPT_NOARG).
But after we've inspected a callback and determined that all of its
callers use the right flags, what do we do next? We'd like to silence
the compiler warning, but do so in a way that will catch any wrong calls
in the future.
We can do that by actually checking those variables and asserting that
they match our expectations. Because this is such a common pattern,
we'll introduce some helper macros. The resulting messages aren't
as descriptive as we could make them, but the file/line information from
BUG() is enough to identify the problem (and anyway, the point is that
these should never be seen).
Each of the annotated callbacks in this patch triggers
-Wunused-parameters, and was manually inspected to make sure all callers
use the correct options (so none of these BUGs should be triggerable).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-05 06:45:42 +00:00
|
|
|
BUG_ON_OPT_ARG(arg);
|
|
|
|
|
2011-08-11 09:15:38 +00:00
|
|
|
if (unset)
|
|
|
|
/* --no-quiet, --no-verbose */
|
|
|
|
*target = 0;
|
|
|
|
else if (opt->short_name == 'v') {
|
|
|
|
if (*target >= 0)
|
|
|
|
(*target)++;
|
|
|
|
else
|
|
|
|
*target = 1;
|
|
|
|
} else {
|
|
|
|
if (*target <= 0)
|
|
|
|
(*target)--;
|
|
|
|
else
|
|
|
|
*target = -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-07 16:06:14 +00:00
|
|
|
int parse_opt_commits(const struct option *opt, const char *arg, int unset)
|
2011-08-11 09:15:38 +00:00
|
|
|
{
|
2017-05-06 22:09:59 +00:00
|
|
|
struct object_id oid;
|
2011-08-11 09:15:38 +00:00
|
|
|
struct commit *commit;
|
|
|
|
|
assert NOARG/NONEG behavior of parse-options callbacks
When we define a parse-options callback, the flags we put in the option
struct must match what the callback expects. For example, a callback
which does not handle the "unset" parameter should only be used with
PARSE_OPT_NONEG. But since the callback and the option struct are not
defined next to each other, it's easy to get this wrong (as earlier
patches in this series show).
Fortunately, the compiler can help us here: compiling with
-Wunused-parameters can show us which callbacks ignore their "unset"
parameters (and likewise, ones that ignore "arg" expect to be triggered
with PARSE_OPT_NOARG).
But after we've inspected a callback and determined that all of its
callers use the right flags, what do we do next? We'd like to silence
the compiler warning, but do so in a way that will catch any wrong calls
in the future.
We can do that by actually checking those variables and asserting that
they match our expectations. Because this is such a common pattern,
we'll introduce some helper macros. The resulting messages aren't
as descriptive as we could make them, but the file/line information from
BUG() is enough to identify the problem (and anyway, the point is that
these should never be seen).
Each of the annotated callbacks in this patch triggers
-Wunused-parameters, and was manually inspected to make sure all callers
use the correct options (so none of these BUGs should be triggerable).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-05 06:45:42 +00:00
|
|
|
BUG_ON_OPT_NEG(unset);
|
|
|
|
|
2011-08-11 09:15:38 +00:00
|
|
|
if (!arg)
|
|
|
|
return -1;
|
2023-03-28 13:58:46 +00:00
|
|
|
if (repo_get_oid(the_repository, arg, &oid))
|
2011-08-11 09:15:38 +00:00
|
|
|
return error("malformed object name %s", arg);
|
2018-06-29 01:21:58 +00:00
|
|
|
commit = lookup_commit_reference(the_repository, &oid);
|
2011-08-11 09:15:38 +00:00
|
|
|
if (!commit)
|
|
|
|
return error("no such commit %s", arg);
|
|
|
|
commit_list_insert(commit, opt->value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-04-17 14:30:39 +00:00
|
|
|
int parse_opt_commit(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
struct object_id oid;
|
|
|
|
struct commit *commit;
|
|
|
|
struct commit **target = opt->value;
|
|
|
|
|
2020-09-30 12:29:02 +00:00
|
|
|
BUG_ON_OPT_NEG(unset);
|
|
|
|
|
2019-04-17 14:30:39 +00:00
|
|
|
if (!arg)
|
|
|
|
return -1;
|
2023-03-28 13:58:46 +00:00
|
|
|
if (repo_get_oid(the_repository, arg, &oid))
|
2019-04-17 14:30:39 +00:00
|
|
|
return error("malformed object name %s", arg);
|
|
|
|
commit = lookup_commit_reference(the_repository, &oid);
|
|
|
|
if (!commit)
|
|
|
|
return error("no such commit %s", arg);
|
|
|
|
*target = commit;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-07 16:06:08 +00:00
|
|
|
int parse_opt_object_name(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
2017-03-26 16:01:31 +00:00
|
|
|
struct object_id oid;
|
2015-07-07 16:06:08 +00:00
|
|
|
|
|
|
|
if (unset) {
|
2017-03-31 01:40:00 +00:00
|
|
|
oid_array_clear(opt->value);
|
2015-07-07 16:06:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!arg)
|
|
|
|
return -1;
|
2023-03-28 13:58:46 +00:00
|
|
|
if (repo_get_oid(the_repository, arg, &oid))
|
2015-07-07 16:06:08 +00:00
|
|
|
return error(_("malformed object name '%s'"), arg);
|
2017-03-31 01:40:00 +00:00
|
|
|
oid_array_append(opt->value, &oid);
|
2015-07-07 16:06:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-04-17 14:30:40 +00:00
|
|
|
int parse_opt_object_id(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
struct object_id oid;
|
|
|
|
struct object_id *target = opt->value;
|
|
|
|
|
|
|
|
if (unset) {
|
2021-04-26 01:02:56 +00:00
|
|
|
oidcpy(target, null_oid());
|
2019-04-17 14:30:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!arg)
|
|
|
|
return -1;
|
2023-03-28 13:58:46 +00:00
|
|
|
if (repo_get_oid(the_repository, arg, &oid))
|
2019-04-17 14:30:40 +00:00
|
|
|
return error(_("malformed object name '%s'"), arg);
|
|
|
|
*target = oid;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-08-11 09:15:38 +00:00
|
|
|
int parse_opt_tertiary(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
int *target = opt->value;
|
assert NOARG/NONEG behavior of parse-options callbacks
When we define a parse-options callback, the flags we put in the option
struct must match what the callback expects. For example, a callback
which does not handle the "unset" parameter should only be used with
PARSE_OPT_NONEG. But since the callback and the option struct are not
defined next to each other, it's easy to get this wrong (as earlier
patches in this series show).
Fortunately, the compiler can help us here: compiling with
-Wunused-parameters can show us which callbacks ignore their "unset"
parameters (and likewise, ones that ignore "arg" expect to be triggered
with PARSE_OPT_NOARG).
But after we've inspected a callback and determined that all of its
callers use the right flags, what do we do next? We'd like to silence
the compiler warning, but do so in a way that will catch any wrong calls
in the future.
We can do that by actually checking those variables and asserting that
they match our expectations. Because this is such a common pattern,
we'll introduce some helper macros. The resulting messages aren't
as descriptive as we could make them, but the file/line information from
BUG() is enough to identify the problem (and anyway, the point is that
these should never be seen).
Each of the annotated callbacks in this patch triggers
-Wunused-parameters, and was manually inspected to make sure all callers
use the correct options (so none of these BUGs should be triggerable).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-05 06:45:42 +00:00
|
|
|
|
|
|
|
BUG_ON_OPT_ARG(arg);
|
|
|
|
|
2011-08-11 09:15:38 +00:00
|
|
|
*target = unset ? 2 : 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-02-09 15:56:47 +00:00
|
|
|
static size_t parse_options_count(const struct option *opt)
|
|
|
|
{
|
|
|
|
size_t n = 0;
|
|
|
|
|
|
|
|
for (; opt && opt->type != OPTION_END; opt++)
|
|
|
|
n++;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2019-03-29 10:39:04 +00:00
|
|
|
struct option *parse_options_dup(const struct option *o)
|
|
|
|
{
|
2020-02-09 15:58:42 +00:00
|
|
|
struct option no_options[] = { OPT_END() };
|
|
|
|
|
|
|
|
return parse_options_concat(o, no_options);
|
2019-03-29 10:39:04 +00:00
|
|
|
}
|
|
|
|
|
2020-02-09 15:57:56 +00:00
|
|
|
struct option *parse_options_concat(const struct option *a,
|
|
|
|
const struct option *b)
|
2011-08-11 09:15:38 +00:00
|
|
|
{
|
2016-07-05 20:44:47 +00:00
|
|
|
struct option *ret;
|
2020-02-09 15:56:47 +00:00
|
|
|
size_t a_len = parse_options_count(a);
|
|
|
|
size_t b_len = parse_options_count(b);
|
2016-07-05 20:44:47 +00:00
|
|
|
|
|
|
|
ALLOC_ARRAY(ret, st_add3(a_len, b_len, 1));
|
2020-02-09 15:55:54 +00:00
|
|
|
COPY_ARRAY(ret, a, a_len);
|
|
|
|
COPY_ARRAY(ret + a_len, b, b_len + 1); /* + 1 for final OPTION_END */
|
2016-07-05 20:44:47 +00:00
|
|
|
|
|
|
|
return ret;
|
2011-08-11 09:15:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int parse_opt_string_list(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
struct string_list *v = opt->value;
|
|
|
|
|
|
|
|
if (unset) {
|
|
|
|
string_list_clear(v, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!arg)
|
|
|
|
return -1;
|
|
|
|
|
parse_opt_string_list: stop allocating new strings
The parse_opt_string_list callback is basically a thin
wrapper to string_list_append() any string options we get.
However, it calls:
string_list_append(v, xstrdup(arg));
which duplicates the option value. This is wrong for two
reasons:
1. If the string list has strdup_strings set, then we are
making an extra copy, which is simply leaked.
2. If the string list does not have strdup_strings set,
then we pass memory ownership to the string list, but
it does not realize this. If we later call
string_list_clear(), which can happen if "--no-foo" is
passed, then we will leak all of the existing entries.
Instead, we should just pass the argument straight to
string_list_append, and it can decide whether to copy or not
based on its strdup_strings flag.
It's possible that some (buggy) caller could be relying on
this extra copy (e.g., because it parses some options from
an allocated argv array and then frees the array), but it's
not likely. For one, we generally only use parse_options on
the argv given to us in main(). And two, such a caller is
broken anyway, because other option types like OPT_STRING()
do not make such a copy. This patch brings us in line with
them.
Noticed-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-06-13 05:39:12 +00:00
|
|
|
string_list_append(v, arg);
|
2011-08-11 09:15:38 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2011-09-28 17:44:30 +00:00
|
|
|
|
2023-04-10 09:08:28 +00:00
|
|
|
int parse_opt_strvec(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
struct strvec *v = opt->value;
|
|
|
|
|
|
|
|
if (unset) {
|
|
|
|
strvec_clear(v);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!arg)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
strvec_push(v, arg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-28 17:44:30 +00:00
|
|
|
int parse_opt_noop_cb(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2015-06-14 08:41:48 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Recreates the command-line option in the strbuf.
|
|
|
|
*/
|
|
|
|
static int recreate_opt(struct strbuf *sb, const struct option *opt,
|
|
|
|
const char *arg, int unset)
|
|
|
|
{
|
|
|
|
strbuf_reset(sb);
|
|
|
|
|
|
|
|
if (opt->long_name) {
|
|
|
|
strbuf_addstr(sb, unset ? "--no-" : "--");
|
|
|
|
strbuf_addstr(sb, opt->long_name);
|
|
|
|
if (arg) {
|
|
|
|
strbuf_addch(sb, '=');
|
|
|
|
strbuf_addstr(sb, arg);
|
|
|
|
}
|
|
|
|
} else if (opt->short_name && !unset) {
|
|
|
|
strbuf_addch(sb, '-');
|
|
|
|
strbuf_addch(sb, opt->short_name);
|
|
|
|
if (arg)
|
|
|
|
strbuf_addstr(sb, arg);
|
|
|
|
} else
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* For an option opt, recreates the command-line option in opt->value which
|
|
|
|
* must be an char* initialized to NULL. This is useful when we need to pass
|
|
|
|
* the command-line option to another command. Since any previous value will be
|
|
|
|
* overwritten, this callback should only be used for options where the last
|
|
|
|
* one wins.
|
|
|
|
*/
|
|
|
|
int parse_opt_passthru(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
static struct strbuf sb = STRBUF_INIT;
|
|
|
|
char **opt_value = opt->value;
|
|
|
|
|
|
|
|
if (recreate_opt(&sb, opt, arg, unset) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2016-10-08 14:14:57 +00:00
|
|
|
free(*opt_value);
|
2015-06-14 08:41:48 +00:00
|
|
|
|
|
|
|
*opt_value = strbuf_detach(&sb, NULL);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2015-06-14 08:41:49 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* For an option opt, recreate the command-line option, appending it to
|
2020-07-28 20:25:12 +00:00
|
|
|
* opt->value which must be a strvec. This is useful when we need to pass
|
2015-06-14 08:41:49 +00:00
|
|
|
* the command-line option, which can be specified multiple times, to another
|
|
|
|
* command.
|
|
|
|
*/
|
|
|
|
int parse_opt_passthru_argv(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
static struct strbuf sb = STRBUF_INIT;
|
2020-07-28 20:25:12 +00:00
|
|
|
struct strvec *opt_value = opt->value;
|
2015-06-14 08:41:49 +00:00
|
|
|
|
|
|
|
if (recreate_opt(&sb, opt, arg, unset) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2020-07-28 20:25:12 +00:00
|
|
|
strvec_push(opt_value, sb.buf);
|
2015-06-14 08:41:49 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
branch: add flags and config to inherit tracking
It can be helpful when creating a new branch to use the existing
tracking configuration from the branch point. However, there is
currently not a method to automatically do so.
Teach git-{branch,checkout,switch} an "inherit" argument to the
"--track" option. When this is set, creating a new branch will cause the
tracking configuration to default to the configuration of the branch
point, if set.
For example, if branch "main" tracks "origin/main", and we run
`git checkout --track=inherit -b feature main`, then branch "feature"
will track "origin/main". Thus, `git status` will show us how far
ahead/behind we are from origin, and `git pull` will pull from origin.
This is particularly useful when creating branches across many
submodules, such as with `git submodule foreach ...` (or if running with
a patch such as [1], which we use at $job), as it avoids having to
manually set tracking info for each submodule.
Since we've added an argument to "--track", also add "--track=direct" as
another way to explicitly get the original "--track" behavior ("--track"
without an argument still works as well).
Finally, teach branch.autoSetupMerge a new "inherit" option. When this
is set, "--track=inherit" becomes the default behavior.
[1]: https://lore.kernel.org/git/20180927221603.148025-1-sbeller@google.com/
Signed-off-by: Josh Steadmon <steadmon@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-21 03:30:23 +00:00
|
|
|
|
|
|
|
int parse_opt_tracking_mode(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
if (unset)
|
|
|
|
*(enum branch_track *)opt->value = BRANCH_TRACK_NEVER;
|
|
|
|
else if (!arg || !strcmp(arg, "direct"))
|
|
|
|
*(enum branch_track *)opt->value = BRANCH_TRACK_EXPLICIT;
|
|
|
|
else if (!strcmp(arg, "inherit"))
|
|
|
|
*(enum branch_track *)opt->value = BRANCH_TRACK_INHERIT;
|
|
|
|
else
|
|
|
|
return error(_("option `%s' expects \"%s\" or \"%s\""),
|
|
|
|
"--track", "direct", "inherit");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|