At this stage on the journey to a fully built-in `git add`, we already
have everything we need, including the `--interactive` and `--patch`
options, as long as the `add.interactive.useBuiltin` setting is set to
`true` (kind of a "turned off feature flag", which it will be for a
while, until we get confident enough that the built-in version does the
job, and retire the Perl script).
However, the internal `add--interactive` helper is also used to back the
`--patch` option of `git stash`, `git reset` and `git checkout`.
This patch series brings them "online".
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Out of all the patch series on the journey to provide `git add
--interactive` and `git add --patch` in a built-in versions, this is the
big one, as can be expected from the fact that the `git add --patch`
functionality makes up over half of the 1,800+ lines of
`git-add--interactive.perl`.
The two patches that stick out are of course the ones to implement hunk
splitting and hunk editing: these operations are fundamentally more
complicated, and less obvious, than the rest of the operations.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
While re-implementing `git add -i` and `git add -p` in C, I tried to
make sure that there is test coverage for all of the features I convert
from Perl to C, to give me some confidence in the correctness from
running the test suite both with `GIT_TEST_ADD_I_USE_BUILTIN=true` and
with `GIT_TEST_ADD_I_USE_BUILTIN=false`.
However, I discovered that there are a couple of gaps. This patch series
intends to close them.
The first patch might actually not be considered a gap by some: it
basically removes the need for the `TTY` prerequisite in the `git add
-i` tests to verify that the output is colored all right. This change is
rather crucial for me, though: on Windows, where the conversion to a
built-in shows the most obvious benefits, there are no pseudo terminals
(yet), therefore `git.exe` cannot work with them (even if the MSYS2 Perl
interpreter used by Git for Windows knows about some sort of pty
emulation). And I *really* wanted to make sure that the colors work on
Windows, as I personally get a lot out of those color cues.
The patch series ends by addressing two issues that are not exactly
covering testing gaps:
- While adding a test case, I noticed that `git add -p` exited with
*success* when it could not even generate a diff. This is so obviously
wrong that I had to fix it right away (I noticed, actually, because my
in-progress built-in `git add -p` failed, and the Perl version did
not), and I used the same test case to verify that this is fixed once
and for all.
- While working on covering those test gaps, I noticed a problem in an
early version of the built-in version of `git add -p` where the `git
apply --allow-overlap` mode failed to work properly, for little
reason, and I fixed it real quick.
It would seem that the `--allow-overlap` function is not only
purposefully under-documented, but also purposefully under-tested,
probably to discourage its use. I do not quite understand what I
perceive to be Junio's aversion to that option, but I did not feel
like I should put up a battle here, so I did not accompany this fix
with a new test script.
In the end, the built-in version of `git add -p` does not use the
`--allow-overlap` function at all, anyway. Which should make everybody
a lot happier.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This patch series implements the rest of the commands in `git add -i`'s
main loop: `update`, `revert`, `add_untracked`, `patch`, `diff`, and
`quit`. Apart from `quit`, these commands are all very similar in that
they first build a list of files, display it, let the user choose which
ones to act on, and then perform the action.
Note that the `patch` command is not actually converted to C, not
completely at least: the built-in version simply hands off to `git
add--interactive` after letting the user select which files to act on.
The reason for this omission is practicality. Out of the 1,800+ lines of
`git-add--interactive.perl`, over a thousand deal *just* with the `git
add -p` part. I did convert that functionality already (to be
contributed in a separate patch series), discovering that there is so
little overlap between the `git add --patch` part and the rest of `git
add --interactive` that I could put the former into a totally different
file: `add-patch.c`. Just a teaser ;-)
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The built-in `git add -i` machinery obviously has its `the_repository`
structure initialized at the point where `cmd_commit()` calls it, and
therefore does not look at the environment variable `GIT_INDEX_FILE`.
But it has to, because the index was already locked, and we want to ask
the interactive add machinery to work on the `index.lock` file instead
of the `index` file.
Technically, we could teach `run_add_i()` (and `run_add_p()`) to look
specifically at that environment variable, but the entire idea of
passing in a parameter of type `struct repository *` is to allow working
on multiple repositories (and their index files) independently.
So let's instead override the `index_file` field of that structure
temporarily.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This is a straight-forward port of 2f0896ec3a (restore: support
--patch, 2019-04-25) which added support for `git restore -p`.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This patch teaches the built-in `git add -p` machinery all the tricks it
needs to know in order to act as the work horse for `git checkout -p`.
Apart from the minor changes (slightly reworded messages, different
`diff` and `apply --check` invocations), it requires a new function to
actually apply the changes, as `git checkout -p` is a bit special in
that respect: when the desired changes do not apply to the index, but
apply to the work tree, Git does not fail straight away, but asks the
user whether to apply the changes to the worktree at least.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The scripted version of `git stash` called directly into the Perl script
`git-add--interactive.perl`, and this was faithfully converted to C.
However, we have a much better way to do this now: call `git add
--patch=<mode>`, which incidentally also respects the config setting
`add.interactive.useBuiltin`.
Let's do this.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
As `git add` traditionally did not expose the `--patch=<mode>` modes via
command-line options, the scripted version of `git stash` had to call
`git add--interactive` directly.
But this prevents the built-in `add -p` from kicking in, as
`add--interactive` is the Perl script.
So let's introduce support for an optional `<mode>` argument in `git add
--patch[=<mode>]`, and use that in the scripted version of `git stash
-p`, so that the built-in interactive add can do its job if configured.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This patch will make `git add -p` show "No changes." or "Only binary
files changed." in that case.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The `git stash` and `git reset` commands support a `--patch` option, and
both simply hand off to `git add -p` to perform that work. Let's teach
the built-in version of `git add -p` do perform that work, too.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
When displaying the only hunk in a file's diff, the prompt already
excludes the commands to navigate to the previous/next hunk.
Let's also let the `?` command show only the help lines corresponding to
the commands that are displayed in the prompt.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The Perl script backing `git add -p` is used not only for that command,
but also for `git stash -p`, `git reset -p` and `git checkout -p`.
In preparation for teaching the C version of `git add -p` to support
also the latter commands, let's abstract away what is "stage" specific
into a dedicated data structure describing the differences between the
patch modes.
As we prepare for calling the built-in `git add -p` in
`run_add_interactive()` via code paths that have not let `add_config()`
do its work, we have to make sure to re-parse the config using that
function in those cases.
Finally, please note that the Perl version tries to make sure that the
diffs are only generated for the modified files. This is not actually
necessary, as the calls to Git's diff machinery already perform that
work, and perform it well. This makes it unnecessary to port the
`FILTER` field of the `%patch_modes` struct, as well as the
`get_diff_reference()` function.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This command is actually very similar to the 'd' ("do not stage this
hunk or any of the later hunks in the file") command: it just does
something on top, namely leave the loop and return a value indicating
that we're quittin'.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This patch implements the hunk searching feature in the C version of
`git add -p`.
A test is added to verify that this behavior matches the one of the Perl
version of `git add -p`.
Note that this involves a change of behavior: the Perl version uses (of
course) the Perl flavor of regular expressions, while this patch uses
the regcomp()/regexec(), i.e. POSIX extended regular expressions. In
practice, this behavior change is unlikely to matter.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
With this patch, it is now possible to see a summary of the available
hunks and to navigate between them (by number).
A test is added to verify that this behavior matches the one of the Perl
version of `git add -p`.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Just like `git add --edit` allows the user to edit the diff before it is
being applied to the index, this feature allows the user to edit the
diff *hunk*.
Naturally, it gets a bit more complicated here because the result has
to play well with the remaining hunks of the overall diff. Therefore,
we have to do a loop in which we let the user edit the hunk, then test
whether the result would work, and if not, drop the edits and let the
user decide whether to try editing the hunk again.
Note: in contrast to the Perl version, we use the same diff
"coalescing" (i.e. merging overlapping hunks into a single one) also for
the check after editing, and we introduce a new flag for that purpose
that asks the `reassemble_patch()` function to pretend that all hunks
were selected for use.
This allows us to continue to run `git apply` *without* the
`--allow-overlap` option (unlike the Perl version), and it also fixes
two known breakages in `t3701-add-interactive.sh` (which we cannot mark
as resolved so far because the Perl script version is still the default
and continues to have those breakages).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This helper supports the scenario where Git has a populated `strbuf` and
wants to let the user edit it interactively.
In `git add -p`, we will use this to allow interactive hunk editing: the
diff hunks are already in memory, but we need to write them out to a
file so that an editor can be launched, then read everything back once
the user is done editing.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This is considered "the right thing to do", according to 933e44d3a0
("add -p": work-around an old laziness that does not coalesce hunks,
2011-04-06).
Note: we cannot simply modify the hunks while merging them; Once we
implement hunk editing, we will call `reassemble_patch()` whenever a
hunk is edited, therefore we must not modify the hunks (because the user
might e.g. hit `K` and change their mind whether to stage the previous
hunk).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
If this developer's workflow is any indication, then this is *the* most
useful feature of Git's interactive `add `command.
Note: once again, this is not a verbatim conversion from the Perl code
to C: the `hunk_splittable()` function, for example, essentially did all
the work of splitting the hunk, just to find out whether more than one
hunk would have been the result (and then tossed that result into the
trash). In C we instead count the number of resulting hunks (without
actually doing the work of splitting, but just counting the transitions
from non-context lines to context lines), and store that information
with the hunk, and we do that *while* parsing the diff in the first
place.
Another deviation: the built-in `git add -p` was designed with a single
strbuf holding the diff (and another one holding the colored diff, if
that one was asked for) in mind, and hunks essentially store just the
start and end offsets pointing into that strbuf. As a consequence, when
we split hunks, we now use a special mode where the hunk header is
generated dynamically, and only the rest of the hunk is stored using
such start/end offsets. This way, we also avoid the frequent
formatting/re-parsing of the hunk header of the Perl version.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Just like the Perl version, we now helpfully ask the user whether they
want to stage a mode change, or a deletion.
Note that we define the prompts in an array, in preparation for a later
patch that changes those prompts to yet different versions for `git
reset -p`, `git stash -p` and `git checkout -p` (which all call the `git
add -p` machinery to do the actual work).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This imitates the way the Perl version treats mode changes: it offers
the mode change up for the user to decide, as if it was a diff hunk.
In contrast to the Perl version, we make use of the fact that the mode
line is the first hunk, and explicitly strip out that line from the diff
header if that "hunk" was not selected to be applied, and skipping that
hunk while coalescing the diff. The Perl version plays some kind of diff
line lego instead.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This addresses the same problem as 24ab81ae4d (add-interactive: handle
deletion of empty files, 2009-10-27), although in a different way: we
not only stick the "deleted file" line into its own pseudo hunk, but
also the entire remainder (if any) of the same diff.
That way, we do not have to play any funny games with regards to
coalescing the diff after the user selected what (possibly pseudo-)hunks
to stage.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
For simplicity, the initial implementation in C handled only a single
modified file. Now it handles an arbitrary number of files.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
... just like the Perl version ;-)
Note that this requires the `get_add_i_color()` function being defined
globally, which is the entire reason why we gave it such a descriptive
name in the first place.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
When skipping a hunk that adds a different number of lines than it
removes, we need to adjust the subsequent hunk headers of non-skipped
hunks: in pathological cases, the context is not enough to determine
precisely where the patch should be applied.
This problem was identified in 23fea4c240 (t3701: add failing test for
pathological context lines, 2018-03-01) and fixed in the Perl version in
fecc6f3a68 (add -p: adjust offsets of subsequent hunks when one is
skipped, 2018-03-01).
And this patch fixes it in the C version of `git add -p`.
In contrast to the Perl version, we try to keep the extra text on the
hunk header (which typically contains the signature of the function
whose code is changed in the hunk) intact.
Note: while the C version does not support staging mode changes at this
stage, we already prepare for this by simply skipping the hunk header if
both old and new offset is 0 (this cannot happen for regular hunks, and
we will use this as an indicator that we are looking at a special hunk).
Likewise, we already prepare for hunk splitting by handling the absence
of extra text in the hunk header gracefully: only the first split hunk
will have that text, the others will not (indicated by an empty extra
text start/end range). Preparing for hunk splitting already at this
stage avoids an indentation change of the entire hunk header-printing
block later, and is almost as easy to review as without that handling.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Just like the Perl version, we now generate two diffs if `color.diff` is
set: one with and one without color. Then we parse them in parallel and
record which hunks start at which offsets in both.
Note that this is a (slight) deviation from the way the Perl version did
it: we are no longer reading the output of `diff-files` line by line
(which is more natural for Perl than for C), but in one go, and parse
everything later, so we might just as well do it in synchrony.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The code in `git-add--interactive.perl` that takes care of the `patch`
command can look quite intimidating. There are so many modes in which it
can be called, for example.
But for the `patch` command in `git add -i`, only one mode is relevant:
the `stage` mode. And we just implemented the beginnings of that mode in
C so far. So let's use it when `add.interactive.useBuiltin=true`.
Now, while the code in `add-patch.c` is far from reaching feature parity
with the code in `git-add--interactive.perl` (color is not implemented,
the diff algorithm cannot be configured, the colored diff cannot be
post-processed via `interactive.diffFilter`, many commands are
unimplemented yet, etc), hooking it all up with the part of `git add -i`
that is already converted to C makes it easier to test and develop it.
Note: at this stage, both the `add.interactive.useBuiltin` config
setting is still safely opt-in, and will probably be fore quite some
time, to allow for thorough testing "in the wild" without adversely
affecting existing users.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Yes, yes, this is supposed to be only a band-aid option for `git add -p`
not Doing The Right Thing. But as long as we carry the `--allow-overlap`
option, we might just as well get it right.
This fixes the case where one hunk inserts a line before the first line,
and is followed by a hunk whose context overlaps with the first one's
and which appends a line at the end.
Note that this affects only the beginning of the file: when a hunk is
plit into two, the first can change the context so that the second hunk
thinks it should match the beginning of the file, but it no longer does
because the first hunk was already applied. The same is not true for the
end of the file, as the hunks are applied in order (by line numbers):
the hunk that changes the end of the file is by definition the last hunk
to be applied.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
In the previous steps, we re-implemented the main loop of `git add -i`
in C, and most of the commands.
Notably, we left out the actual functionality of `patch`, as the
relevant code makes up more than half of `git-add--interactive.perl`,
and is actually pretty independent of the rest of the commands.
With this commit, we start to tackle that `patch` part. For better
separation of concerns, we keep the code in a separate file,
`add-patch.c`. The new code is still guarded behind the
`add.interactive.useBuiltin` config setting, and for the moment,
it can only be called via `git add -p`.
The actual functionality follows the original implementation of
5cde71d64a (git-add --interactive, 2006-12-10), but not too closely
(for example, we use string offsets rather than copying strings around,
and we also remember which previous/next hunk was undecided, rather than
looking again when the user asked to jump there).
As a further deviation from that commit, We also use a comma instead of
a slash to separate the available commands in the prompt, as the current
version of the Perl script does this, and we also add a line about the
question mark ("print help") to the help text.
While it is tempting to use this conversion of `git add -p` as an excuse
to work on `apply_all_patches()` so that it does _not_ want to read a
file from `stdin` or from a file, but accepts, say, an `strbuf` instead,
we will refrain from this particular rabbit hole at this stage.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The first thing `git add -p` does is to generate a diff. If this diff
cannot be generated, `git add -p` should not continue as if nothing
happened, but instead fail.
What we *actually* do here is much broader: we now verify for *every*
`run_cmd_pipe()` call that the spawned process actually succeeded.
Note that we have to change two callers in this patch, as we need to
store the spawned process' output in a local variable, which means that
the callers can no longer decide whether to interpret the `return <$fh>`
in array or in scalar context.
This bug was noticed while writing a test case for the diff.algorithm
feature, and we let that test case double as a regression test for this
fixed bug, too.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Without this patch, there is actually no test in Git's test suite that
covers the diff.algorithm feature. Let's add one.
We do this by passing a bogus value and then expecting `git diff-files`
to produce the appropriate error message.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
In preparation for re-implementing `git add -p` in pure C (where we will
purposefully keep the implementation of `git add -p` separate from the
implementation of `git add -i`), let's verify that the user is told the
same things as in the Perl version when the diff file is either empty or
contains only entries about binary files.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The `git add -p` command offers different prompts for regular diff hunks
vs mode change pseudo hunks vs diffs deleting files.
Let's cover this in the regresion test suite, in preparation for
re-implementing `git add -p` in C.
For the mode change prompt, we use a trick that lets this test case pass
even on systems without executable bit, i.e. where `core.filemode =
false` (such as Windows): we first add the file to the index with `git
add --chmod=+x`, and then call `git add -p` with `core.filemode` forced
to `true`. The file on disk has no executable bit set, therefore we will
see a mode change.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The TTY prerequisite is a rather heavy one: it not only requires Perl to
work, but also the IO/Pty.pm module (with native support, and it
requires pseudo terminals, too).
In particular, test cases marked with the TTY prerequisite would be
skipped in Git for Windows' SDK.
In the case of `git add -p`, we do not actually need that big a hammer,
as we do not want to test any functionality that requires a pseudo
terminal; all we want is for the interactive add command to use color,
even when being called from within the test suite.
And we found exactly such a trick earlier already: when we added a test
case to verify that the main loop of `git add -i` is colored
appropriately. Let's use that trick instead of the TTY prerequisite.
While at it, we avoid the pipes, as we do not want a SIGPIPE to break
the regression test cases (which will be much more likely when we do not
run everything through Perl because that is inherently slower).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
In this developer's workflows, it often happens that a hunk needs to be
edited in a way that adds lines, and sometimes even reduces the number
of context lines.
Let's add a regression test for this.
Note that just like the preceding test case, the new test case is *not*
handled gracefully by the current `git add -p`. It will be handled
correctly by the upcoming built-in `git add -p`, though.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
It is not only laziness that we simply spawn `git diff -p --cached`
here: this command needs to use the pager, and the pager needs to exit
when the diff is done. Currently we do not have any way to make that
happen if we run the diff in-process. So let's just spawn.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Well, it is not a full implementation yet. In the interest of making
this easy to review (and easy to keep bugs out), we still hand off to
the Perl script to do the actual work.
The `patch` functionality actually makes up for more than half of the
1,800+ lines of `git-add--interactive.perl`. It will be ported from Perl
to C incrementally, later.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This is yet another command, ported to C. It builds nicely on the
support functions introduced for other commands, with the notable
difference that only names are displayed for untracked files, no
file type or diff summary.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This is a relatively straight-forward port from the Perl version, with
the notable exception that we imitate `git reset -- <paths>` in the C
version rather than the convoluted `git ls-tree HEAD -- <paths> | git
update-index --index-info` followed by `git update-index --force-remove
-- <paths>` for the missed ones.
While at it, we fix the pretty obvious bug where the `revert` command
offers to unstage files that do not have staged changes.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
After `status` and `help`, it is now time to port the `update` command
to C, the second command that is shown in the main loop menu of `git add
-i`.
This `git add -i` command is the first one which lets the user choose a
subset of a list of files, and as such, this patch lays the groundwork
for the other commands of that category:
- It teaches the `print_file_item()` function to show a unique prefix
if we found any (the code to find it had been added already in the
previous patch where we colored the unique prefixes of the main loop
commands, but that patch uses the `print_command_item()` function to
display the menu items).
- This patch also adds the help text that is shown when the user input
to select items from the shown list could not be parsed.
- As `get_modified_files()` clears the list of files, it now has to take
care of clearing the _full_ `prefix_item_list` lest the `sorted` and
`selected` fields go stale and inconsistent.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The `update`, `revert` and `add-untracked` commands allow selecting
multiple entries. Let's extend the `list_and_choose()` function to
accommodate those use cases.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
In the `update` command of `git add -i`, we are primarily interested in the
list of modified files that have worktree (i.e. unstaged) changes.
At the same time, we need to determine _also_ the staged changes, to be
able to produce the full added/deleted information.
The Perl script version of `git add -i` has a parameter of the
`list_modified()` function for that matter. In C, we can be a lot more
precise, using an `enum`.
The C implementation of the filter also has an easier time to avoid
unnecessary work, simply by using an adaptive order of the `diff-index`
and `diff-files` phases, and then skipping files in the second phase
when they have not been seen in the first phase.
Seeing as we change the meaning of the `phase` field, we rename it to
`mode` to reflect that the order depends on the exact invocation of the
`git add -i` command.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
During a review, Junio Hamano pointed out that the `rev.prune_data` was
copied from another pathspec but never cleaned up.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The first part of the long journey to a fully built-in `git add -i`.
It reflects the part that was submitted a couple of times (see
https://github.com/gitgitgadget/git/pull/103) during the Outreachy
project by Slavica Đukić that continued the journey based on an initial
patch series by Daniel Ferreira.
This part only implements the `status` and the `help` part, like
Slavica's last iteration did, in the interest of making the review
remotely more reviewable. I fear that this attempt of making it a bit
more reviewable is pretty futile, as so many things changed. So I will
ask the reviewers for forgiveness: please be kind, and give this sort of
a fresh review.
I threw in a couple of major changes on top of that iteration, though:
- The original plan was to add a helper (`git add--helper`) that takes
over more and more responsibility from the Perl script over the course
of the conversion.
This plan is no longer in effect, as I encountered a serious problem
with that: the MSYS2 runtime used by the Perl interpreter which Git
for Windows employs to run `git add -i` has a curious bug (that is
safely outside the purview of this here patch series) where it fails
to read from standard input after it spawned a non-MSYS2 program that
reads from standard input. To keep my `git add -i` in a working state,
I therefore adopted a different strategy:
Just like `git difftool` was converted by starting with a built-in
that did nothing but handing off to the scripted version, guarded by
the (opt-in) `difftool.useBuiltin` config setting, I start this patch
series by a built-in `add -i` that does nothing else but state that it
is not implemented yet, guarded by the (opt-in)
`add.interactive.useBuiltin` config setting.
In contrast to the `git difftool` situation, it is quite a bit easier
here, as we do not even have to rename the script to
`git-legacy-add--interactive.perl`: the `add--interactive` command is
an implementation detail that users are not even supposed to know
about. Therefore, we can implement that road fork between the built-in
and the scripted version in `builtin/add.c`, i.e. in the user-facing
`git add` command.
This will also naturally help with the transition to a fully built-in
`git add -i`/`git add -p`, as we saw with the built-in `git rebase`
how important it is for end users to have an escape hatch (and for
that reason, tried our best to provide the same with the built-in `git
stash`).
- The `help` command was actually not hooked up in `git add -i`, but was
only available as a special option of the `git add--helper` command.
As that command no longer exists, I kind of *had* to implement
some way to let the built-in `git add -i` show the help text.
- The main loop of `git add -i` (i.e. the thing that lets you choose
`status` or `help`) is now implemented (but only lists `status` and
`help`, of course), as it makes use of that feature that took the main
chunk of the Outreachy project: the function to determine unique
prefixes of a list of strings.
- Speaking of the unique prefixes: the functionality to determine those
is now encapsulated in the `prefix-map.c` file, and I also added a
regression test.
- Speaking of the tests: I also implemented support for the environment
variable `GIT_TEST_ADD_I_USE_BUILTIN`: by setting it, the test suite
can be forced to use the built-in, or the Perl script, version of `git
add -i`. Needless to say: by the end of this patch series, running the
test suite with `GIT_TEST_ADD_I_USE_BUILTIN=true` will still result in
a ton of test failures due to not-yet-implemented commands, but it
will also demonstrate what *already* works.
- Since the main loop starts not only by showing the status, but
refreshes the index before that, I added that, and I actually
refactored that code into a new function
(`repo_refresh_and_write_index()`), as it will be used a couple of
times by the end of the complete conversion of `git add -i` into a
built-in command.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This imitates the code to show the help text from the Perl script
`git-add--interactive.perl` in the built-in version.
To make sure that it renders exactly like the Perl version of `git add
-i`, we also add a test case for that to `t3701-add-interactive.sh`.
Signed-off-by: Slavica Đukić <slawica92@hotmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The error messages as well as the unique prefixes are colored in `git
add -i` by default; We need to do the same in the built-in version.
Signed-off-by: Slavica Đukić <slawica92@hotmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
With this change, we print out the same colored help text that the
Perl-based `git add -i` prints in the main loop when question mark is
entered.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>