Hi Paul,
On Sat, 12 Mar 2016, Paul Tan wrote:
> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index 40176ca..ec63d3b 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c
> @@ -8,6 +8,22 @@
> #include "remote.h"
> #include "branch.h"
> #include "refs.h"
> +#include "rebase-am.h"
> +
> +enum rebase_type {
> + REBASE_TYPE_NONE = 0,
> + REBASE_TYPE_AM
> +};
> +
> +static const char *rebase_dir(enum rebase_type type)
> +{
> + switch (type) {
> + case REBASE_TYPE_AM:
> + return git_path_rebase_am_dir();
> + default:
> + die("BUG: invalid rebase_type %d", type);
> + }
> +}
This is awfully close to what the sequencer sports. So close that I would
call it technical debt.
It would most likely result in easier-to-maintain source code if the
sequencer and the rebase code shared as much as possible (in
sequencer.[ch], for historical reasons).
> diff --git a/rebase-am.c b/rebase-am.c
> new file mode 100644
> index 000..53e8798
> --- /dev/null
> +++ b/rebase-am.c
> @@ -0,0 +1,110 @@
> +#include "cache.h"
> +#include "rebase-am.h"
> +#include "run-command.h"
> +
> +GIT_PATH_FUNC(git_path_rebase_am_dir, "rebase-apply");
> +
> +void rebase_am_init(struct rebase_am *state, const char *dir)
> +{
> + if (!dir)
> + dir = git_path_rebase_am_dir();
> + rebase_options_init(>opts);
> + state->dir = xstrdup(dir);
> +}
Does it really make sense to have completely separate structs for the
different rebase types? I think not. It would not hurt IMO to have a
couple of fields that are only used for certain rebase types but not
others. The benefit of being able to reuse, code would far outweigh that
minimal cost.
It all comes back to my favorite paradigm: DRY. Don't Repeat Yourself.
Another important paradigm is: avoid feautures that you do not use. In
this instance, I have to ask why the init function accepts the "dir"
parameter? Do we ever need it? And if yes, would it make more sense to
introduce the parameter with the patch that actually uses it?
> +
> +void rebase_am_release(struct rebase_am *state)
> +{
> + rebase_options_release(>opts);
> + free(state->dir);
Urgh. The only reason for this free() and the corresponding xstrdup() is
so that the caller *may* release the directory before finishing the rebase
*if* it overrides the directory. That's not very elegant.
Why not simply state (by declaring the field as const char *) that it is
*not* the rebase machinery's duty to take care of the memory management of
this string?
This would simplify the common code flow, especially if it was done to
*all* strings in the state struct.
> +int rebase_am_in_progress(const struct rebase_am *state)
> +{
> + const char *dir = state ? state->dir : git_path_rebase_am_dir();
> + struct stat st;
> +
> + return !lstat(dir, ) && S_ISDIR(st.st_mode);
> +}
This function is sobbing inconsolably for being stuck into the rebase-am
part of the code, with a name that ensures that it will never grow up and
become more useful. Between its miserable life, it dreams of being named
dir_exists() and living the high life next to its buddy, file_exists().
> +int rebase_am_load(struct rebase_am *state)
> +{
> + if (rebase_options_load(>opts, state->dir) < 0)
> + return -1;
> +
> + return 0;
> +}
:-(
This looks like adding code for adding code's sake. Not only does it craft
its own return value instead of reusing rebase_options_load()'s, it is
just wrapping a single, simple statement, therefore its only use is to add
one layer of indirection.
> +static int run_format_patch(const char *patches, const struct object_id
> *left,
> + const struct object_id *right)
> +{
> + struct child_process cp = CHILD_PROCESS_INIT;
> + int ret;
> +
> + cp.git_cmd = 1;
> + cp.out = xopen(patches, O_WRONLY | O_CREAT, 0777);
> + argv_array_push(, "format-patch");
> + argv_array_push(, "-k");
> + argv_array_push(, "--stdout");
> + argv_array_push(, "--full-index");
> + argv_array_push(, "--cherry-pick");
> + argv_array_push(, "--right-only");
> + argv_array_push(, "--src-prefix=a/");
> + argv_array_push(, "--dst-prefix=b/");
> + argv_array_push(, "--no-renames");
> + argv_array_push(, "--no-cover-letter");
> + argv_array_pushf(, "%s...%s", oid_to_hex(left),
> oid_to_hex(right));
> +
> + ret = run_command();
> + close(cp.out);
> + return ret;
> +}
> +
> +static int run_am(const struct rebase_am *state, const char *patches)
> +{
> + struct child_process cp = CHILD_PROCESS_INIT;
> + int ret;
> +
> + cp.git_cmd = 1;
> + cp.in = xopen(patches, O_RDONLY);
> + argv_array_push(, "am");
> + argv_array_push(, "--rebasing");
> + if (state->opts.resolvemsg)
> + argv_array_pushf(, "--resolvemsg=%s",
> state->opts.resolvemsg);
> +
> + ret = run_command();
> + close(cp.in);
> + return ret;
> +}
Yeah, these functions really want