Commit Graph

63986 Commits

Author SHA1 Message Date
Johannes Schindelin
593b715547 Merge 'rebase--helper' into HEAD 2016-10-13 14:27:52 +02:00
Johannes Schindelin
3d75f46f69 Merge 'sequencer-i' into HEAD 2016-10-13 14:27:51 +02:00
Johannes Schindelin
09d4656ba1 rebase -i: use the rebase--helper builtin
Now that the sequencer learned to process a "normal" interactive rebase,
we use it. The original shell script is still used for "non-normal"
interactive rebases, i.e. when --root or --preserve-merges was passed.

Please note that the --root option (via the $squash_onto variable) needs
special handling only for the very first command, hence it is still okay
to use the helper upon continue/skip.

Also please note that the --no-ff setting is volatile, i.e. when the
interactive rebase is interrupted at any stage, there is no record of
it. Therefore, we have to pass it from the shell script to the
rebase--helper.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:47 +02:00
Johannes Schindelin
be819f880b Add a builtin helper for interactive rebases
Git's interactive rebase is still implemented as a shell script, despite
its complexity. This implies that it suffers from the portability point
of view, from lack of expressibility, and of course also from
performance. The latter issue is particularly serious on Windows, where
we pay a hefty price for relying so much on POSIX.

Unfortunately, being such a huge shell script also means that we missed
the train when it would have been relatively easy to port it to C, and
instead piled feature upon feature onto that poor script that originally
never intended to be more than a slightly pimped cherry-pick in a loop.

To open the road toward better performance (in addition to all the other
benefits of C over shell scripts), let's just start *somewhere*.

The approach taken here is to add a builtin helper that at first intends
to take care of the parts of the interactive rebase that are most
affected by the performance penalties mentioned above.

In particular, after we spent all those efforts on preparing the sequencer
to process rebase -i's git-rebase-todo scripts, we implement the `git
rebase -i --continue` functionality as a new builtin, git-rebase--helper.

Once that is in place, we can work gradually on tackling the rest of the
technical debt.

Note that the rebase--helper needs to learn about the transient
--ff/--no-ff options of git-rebase, as the corresponding flag is not
persisted to, and re-read from, the state directory.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:47 +02:00
Johannes Schindelin
4e1aa6b095 sequencer (rebase -i): write out the final message
The shell script version of the interactive rebase has a very specific
final message. Teach the sequencer to print the same.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:46 +02:00
Johannes Schindelin
3affd04204 sequencer (rebase -i): write the progress into files
For the benefit of e.g. the shell prompt, the interactive rebase not
only displays the progress for the user to see, but also writes it into
the msgnum/end files in the state directory.

Teach the sequencer this new trick.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:46 +02:00
Johannes Schindelin
cf4b090249 sequencer (rebase -i): show the progress
The interactive rebase keeps the user informed about its progress.
If the sequencer wants to do the grunt work of the interactive
rebase, it also needs to show that progress.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:46 +02:00
Johannes Schindelin
7c70c11af5 sequencer (rebase -i): suggest --edit-todo upon unknown command
This is the same behavior as known from `git rebase -i`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:46 +02:00
Johannes Schindelin
79742efe09 sequencer (rebase -i): show only failed cherry-picks' output
This is the behavior of the shell script version of the interactive
rebase, by using the `output` function defined in `git-rebase.sh`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:45 +02:00
Johannes Schindelin
315eed6963 sequencer (rebase -i): show only failed git commit's output
This is the behavior of the shell script version of the interactive
rebase, by using the `output` function defined in `git-rebase.sh`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:45 +02:00
Johannes Schindelin
c6b55dae86 run_command_opt(): optionally hide stderr when the command succeeds
This will be needed to hide the output of `git commit` when the
sequencer handles an interactive rebase's script.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:45 +02:00
Johannes Schindelin
061b4d017e sequencer (rebase -i): differentiate between comments and 'noop'
In the upcoming patch, we will support rebase -i's progress
reporting. The progress skips comments but counts 'noop's.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:44 +02:00
Johannes Schindelin
17facd36e9 sequencer (rebase -i): implement the 'drop' command
The parsing part of a 'drop' command is almost identical to parsing a
'pick', while the operation is the same as that of a 'noop'.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:44 +02:00
Johannes Schindelin
bda2de89c1 sequencer (rebase -i): allow rescheduling commands
The interactive rebase has the very special magic that a cherry-pick
that exits with a status different from 0 and 1 signifies a failure to
even record that a cherry-pick was started.

This can happen e.g. when a fast-forward fails because it would
overwrite untracked files.

In that case, we must reschedule the command that we thought we already
had at least started successfully.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:44 +02:00
Johannes Schindelin
d9e61a1efa sequencer (rebase -i): respect strategy/strategy_opts settings
The sequencer already has an idea about using different merge
strategies. We just piggy-back on top of that, using rebase -i's
own settings, when running the sequencer in interactive rebase mode.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:44 +02:00
Johannes Schindelin
37d6a8d49e sequencer (rebase -i): respect the rebase.autostash setting
Git's `rebase` command inspects the `rebase.autostash` config setting
to determine whether it should stash any uncommitted changes before
rebasing and re-apply them afterwards.

As we introduce more bits and pieces to let the sequencer act as
interactive rebase's backend, here is the part that adds support for
the autostash feature.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:44 +02:00
Johannes Schindelin
46397fbe33 sequencer (rebase -i): run the post-rewrite hook, if needed
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:44 +02:00
Johannes Schindelin
2c3a77f533 sequencer (rebase -i): record interrupted commits in rewritten, too
When continuing after a `pick` command failed, we want that commit
to show up in the rewritten-list (and its notes to be rewritten), too.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:44 +02:00
Johannes Schindelin
dc97ac4a05 sequencer (rebase -i): copy commit notes at end
When rebasing commits that have commit notes attached, the interactive
rebase rewrites those notes faithfully at the end. The sequencer must
do this, too, if it wishes to do interactive rebase's job.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:43 +02:00
Johannes Schindelin
bdcfb7e710 sequencer (rebase -i): set the reflog message consistently
We already used the same reflog message as the scripted version of rebase
-i when finishing. With this commit, we do that also for all the commands
before that.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:43 +02:00
Johannes Schindelin
10ab63008d sequencer (rebase -i): refactor setting the reflog message
This makes the code DRYer, with the obvious benefit that we can enhance
the code further in a single place.

We can also reuse the functionality elsewhere by calling this new
function.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:43 +02:00
Johannes Schindelin
dd344bd5f6 sequencer (rebase -i): allow fast-forwarding for edit/reword
The sequencer already knew how to fast-forward instead of
cherry-picking, if possible.

We want to continue to do this, of course, but in case of the 'reword'
command, we will need to call `git commit` after fast-forwarding.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:43 +02:00
Johannes Schindelin
c2a4b08c46 sequencer (rebase -i): implement the 'reword' command
This is now trivial, as all the building blocks are in place: all we need
to do is to flip the "edit" switch when committing.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:43 +02:00
Johannes Schindelin
71e3fd0c3c sequencer (rebase -i): leave a patch upon error
When doing an interactive rebase, we want to leave a 'patch' file for
further inspection by the user (even if we never tried to actually apply
that patch, since we're cherry-picking instead).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:43 +02:00
Johannes Schindelin
84e2e26368 sequencer (rebase -i): update refs after a successful rebase
An interactive rebase operates on a detached HEAD (to keep the reflog
of the original branch relatively clean), and updates the branch only
at the end.

Now that the sequencer learns to perform interactive rebases, it also
needs to learn the trick to update the branch before removing the
directory containing the state of the interactive rebase.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:43 +02:00
Johannes Schindelin
3c78acbef7 sequencer (rebase -i): the todo can be empty when continuing
When the last command of an interactive rebase fails, the user needs to
resolve the problem and then continue the interactive rebase. Naturally,
the todo script is empty by then. So let's not complain about that!

To that end, let's move that test out of the function that parses the
todo script, and into the more high-level function read_populate_todo().
This is also necessary by now because the lower-level parse_insn_buffer()
has no idea whether we are performing an interactive rebase or not.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:43 +02:00
Johannes Schindelin
7fdb7caa86 sequencer (rebase -i): skip some revert/cherry-pick specific code path
When a cherry-pick continues without a "todo script", the intention is
simply to pick a single commit.

However, when an interactive rebase is continued without a "todo
script", it means that the last command has been completed and that we
now need to clean up.

This commit guards the revert/cherry-pick specific steps so that they
are not executed in rebase -i mode.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:42 +02:00
Johannes Schindelin
7569d33f5e sequencer (rebase -i): remove CHERRY_PICK_HEAD when no longer needed
The scripted version of the interactive rebase already does that.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:42 +02:00
Johannes Schindelin
a3e5dbd984 sequencer (rebase -i): allow continuing with staged changes
When an interactive rebase is interrupted, the user may stage changes
before continuing, and we need to commit those changes in that case.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:42 +02:00
Johannes Schindelin
dbe70b6b66 sequencer (rebase -i): write an author-script file
When the interactive rebase aborts, it writes out an author-script file
to record the author information for the current commit. As we are about
to teach the sequencer how to perform the actions behind an interactive
rebase, it needs to write those author-script files, too.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:42 +02:00
Johannes Schindelin
d036424d43 sequencer (rebase -i): implement the short commands
For users' convenience, most rebase commands can be abbreviated, e.g.
'p' instead of 'pick' and 'x' instead of 'exec'. Let's teach the
sequencer to handle those abbreviated commands just fine.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:42 +02:00
Johannes Schindelin
b2c7c683f2 sequencer (rebase -i): add support for the 'fixup' and 'squash' commands
This is a huge patch, and at the same time a huge step forward to
execute the performance-critical parts of the interactive rebase in a
builtin command.

Since 'fixup' and 'squash' are not only similar, but also need to know
about each other (we want to reduce a series of fixups/squashes into a
single, final commit message edit, from the user's point of view), we
really have to implement them both at the same time.

Most of the actual work is done by the existing code path that already
handles the "pick" and the "edit" commands; We added support for other
features (e.g. to amend the commit message) in the patches leading up to
this one, yet there are still quite a few bits in this patch that simply
would not make sense as individual patches (such as: determining whether
there was anything to "fix up" in the "todo" script, etc).

In theory, it would be possible to reuse the fast-forward code path also
for the fixup and the squash code paths, but in practice this would make
the code less readable. The end result cannot be fast-forwarded anyway,
therefore let's just extend the cherry-picking code path for now.

Since the sequencer parses the entire `git-rebase-todo` script in one go,
fixup or squash commands without a preceding pick can be reported early
(in git-rebase--interactive, we could only report such errors just before
executing the fixup/squash).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:42 +02:00
Johannes Schindelin
0cc1904d16 sequencer (rebase -i): write the 'done' file
In the interactive rebase, commands that were successfully processed are
not simply discarded, but appended to the 'done' file instead. This is
used e.g. to display the current state to the user in the output of
`git status` or the progress.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:42 +02:00
Johannes Schindelin
80f7817c0c sequencer (rebase -i): learn about the 'verbose' mode
When calling `git rebase -i -v`, the user wants to see some statistics
after the commits were rebased. Let's show some.

The strbuf we use to perform that task will be used for other things
in subsequent commits, hence it is declared and initialized in a wider
scope than strictly needed here.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:42 +02:00
Johannes Schindelin
494747e7a1 sequencer (rebase -i): implement the 'exec' command
The 'exec' command is a little special among rebase -i's commands, as it
does *not* have a SHA-1 as first parameter. Instead, everything after the
`exec` command is treated as command-line to execute.

Let's reuse the arg/arg_len fields of the todo_item structure (which hold
the oneline for pick/edit commands) to point to the command-line.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:42 +02:00
Johannes Schindelin
6ec43bcbfb sequencer (rebase -i): implement the 'edit' command
This patch is a straight-forward reimplementation of the `edit`
operation of the interactive rebase command.

Well, not *quite* straight-forward: when stopping, the `edit`
command wants to write the `patch` file (which is not only the
patch, but includes the commit message and author information). To
that end, this patch requires the earlier work that taught the
log-tree machinery to respect the `file` setting of
rev_info->diffopt to write to a file stream different than stdout.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:41 +02:00
Johannes Schindelin
e7a3558bee sequencer (rebase -i): implement the 'noop' command
The 'noop' command is probably the most boring of all rebase -i commands
to support in the sequencer.

Which makes it an excellent candidate for this first stab to add support
for rebase -i's commands to the sequencer.

For the moment, let's also treat empty lines and commented-out lines as
'noop'; We will refine that handling later in this patch series.

To make it easier to identify "classes" of todo_commands (such as:
determine whether a command is pick-like, i.e. handles a single commit),
let's enforce a certain order of said commands.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:41 +02:00
Johannes Schindelin
ff32686431 sequencer: support a new action: 'interactive rebase'
This patch introduces a new action for the sequencer. It really does not
do a whole lot of its own right now, but lays the ground work for
patches to come. The intention, of course, is to finally make the
sequencer the work horse of the interactive rebase (the original idea
behind the "sequencer" concept).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:41 +02:00
Johannes Schindelin
a2c01ced5e Merge 'require-clean-work-tree' into HEAD 2016-10-13 14:27:41 +02:00
Johannes Schindelin
6100644598 Merge 'prepare-sequencer' into HEAD 2016-10-13 14:27:40 +02:00
Johannes Schindelin
b0885775f2 Merge 'libify-sequencer' into HEAD 2016-10-13 14:27:39 +02:00
Johannes Schindelin
b4d0c1f8fc wt-status: teach has_{unstaged,uncommitted}_changes() about submodules
Sometimes we are *actually* interested in those changes... For
example when an interactive rebase wants to continue with a staged
submodule update.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:38 +02:00
Johannes Schindelin
c9519d9cf2 Export also the has_un{staged,committed}_changed() functions
They will be used in the upcoming rebase helper.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:38 +02:00
Johannes Schindelin
28717d297a Make the require_clean_work_tree() function truly reusable
It is remarkable that libgit.a did not sport this function yet... Let's
move it into a more prominent (and into an actually reusable) spot:
wt-status.[ch].

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:38 +02:00
Johannes Schindelin
0a38f0c1ce pull: make code more similar to the shell script again
When converting the pull command to a builtin, the
require_clean_work_tree() function was renamed and the pull-specific
parts hard-coded.

This makes it impossible to reuse the code, so let's modify the code to
make it more similar to the original shell script again.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:37 +02:00
Johannes Schindelin
60d59900b9 pull: drop confusing prefix parameter of die_on_unclean_work_tree()
In cmd_pull(), when verifying that there are no changes preventing a
rebasing pull, we diligently pass the prefix parameter to the
die_on_unclean_work_tree() function which in turn diligently passes it
to the has_unstaged_changes() and has_uncommitted_changes() functions.

The casual reader might now be curious (as this developer was) whether
that means that calling `git pull --rebase` in a subdirectory will
ignore unstaged changes in other parts of the working directory. And be
puzzled that `git pull --rebase` (correctly) complains about those
changes outside of the current directory.

The puzzle is easily resolved: while we take pains to pass around the
prefix and even pass it to init_revisions(), the fact that no paths are
passed to init_revisions() ensures that the prefix is simply ignored.

That, combined with the fact that we will *always* want a *full* working
directory check before running a rebasing pull, is reason enough to
simply do away with the actual prefix parameter and to pass NULL
instead, as if we were running this from the top-level working directory
anyway.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:37 +02:00
Johannes Schindelin
0fa9f0dec5 Merge branch 'jh/status-v2-porcelain'
Enhance "git status --porcelain" output by collecting more data on
the state of the index and the working tree files, which may
further be used to teach git-prompt (in contrib/) to make fewer
calls to git.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:37 +02:00
Johannes Schindelin
d6e93bc6e6 sequencer: remove bogus hint for translators
When translating error messages, we need to be careful *not* to translate
the todo commands such as "pick", "reword", etc because they are commands,
and Git would not understand translated versions of those commands.

Therefore, translating the commands in the error messages would simply be
misleading.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:35 +02:00
Johannes Schindelin
4dd4cbca2c sequencer: quote filenames in error messages
This makes the code consistent by fixing quite a couple of error messages.

Suggested by Jakub Narębski.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:35 +02:00
Johannes Schindelin
e8cff2f0a3 sequencer: mark action_name() for translation
The definition of this function goes back all the way to 043a449
(sequencer: factor code out of revert builtin, 2012-01-11), long before a
serious effort was made to translate all the error messages.

It is slightly out of the context of the current patch series (whose
purpose it is to re-implement the performance critical parts of the
interactive rebase in C) to make the error messages in the sequencer
translatable, but what the heck. We'll just do it while we're looking at
this part of the code.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2016-10-13 14:27:35 +02:00