At the moment it doesn't make a big difference, because the vast majority of
callers create a list of todos themselves to completely replace what git came up
with. We're changing this in the following commits though, and then it's helpful
to preserve merges.
It used to work on the assumption that rebasing commits in lazygit's model
correspond one-to-one to lines in the git-rebase-todo file, which isn't
necessarily true (e.g. when users use "git rebase --edit-todo" at the custom
command prompt and add a "break" between lines).
This is useful when working with stacked branches, because you can now move
"pick" entries across an update-ref command and you can tell exactly which
branch the commit will end up in.
It's also useful to spot situations where the --update-refs option didn't work
as desired. For example, if you duplicate a branch and want to rebase only one
of the branches but not the other (maybe for testing); if you have
rebase.updateRefs=true in your git config, then rebasing one branch will move
the other branch along. To solve this we'll have to introduce a way to delete
the update-ref entry (maybe by hitting backspace?); this is out of scope for
this PR, so for now users will have to type "git rebase --edit-todo" into the
custom command prompt to sort this out.
We will also have to prevent users from trying to turn update-ref commands into
other commands like "pick" or "drop"; we'll do this later in this branch.
So far the algorithm worked on the assumption that the output of the "git show"
command corresponds one-to-one to the lines of the rebase-todo file. This
assumption doesn't hold once we start to include todo lines that don't have a
sha (like update-ref), or when the todo file contains multiple entries for the
same sha. This should never happen normally, but it can if users manually edit
the todo file and duplicate a line.
The main reason for doing this (besides the reasons given for Status in the
previous commit) is that it allows us to easily convert from TodoCommand to
Action and back. This will be needed later in the branch. Fortunately,
TodoCommand is one-based, so this allows us to add an ActionNone constant with
the value 0.
This is unrelated to the changes in this PR, but since we are doing the same
thing for the commit.Action field in the next commit, it makes sense to do it
for Status too for consistency. Modelling this as an enum feels more natural
than modelling it as a string, since there's a finite set of possible values.
And it saves a little bit of memory (not very much, since none of the strings
were heap-allocated, but still).
Instead, query the platform defaults only if the config is empty. This will be
necessary later to distinguish an empty config from a default config, so that we
can give deprecation warnings.
The "open" command is supposed to behave in the same way as double-clicking a
file in the Finder/Explorer. The concept of jumping to a specific line in the
file doesn't make sense for this; use "edit" instead.
These files were renamed from os_windows_test.go to os_test_windows.go (etc.) in
95b2e9540a. Since then, the tests have no longer run, since go only looks for
tests in files ending with "test.go".
It isn't important that the file name ends with "_windows.go", since there are
already build constrains in the files themselves.
Pulled this out into a separate commit since it was unrelated to the
feature coming behind it.
This just cleans up the `commit_test.go` file slightly (for the method
that I was working on) so that the tests are built in a way that is
slightly more readable - testing each configuration option individually
without combining any of them.
This fixes the problem that patching would stop at the first file that has a
conflict. We always want to patch all files.
Also, it's faster for large patches, and the code is a little bit simpler too.
All callers in this file now use reverseOnGenerate=false and
keepOriginalHeader=true, so hard-code that in the call to ModifiedPatchForLines
and get rid of the parameters.
The loop is pointless for two reasons:
- git apply --3way has this fallback built in already. If it can't do a
three-way merge, it will fall back to applying the patch normally.
- However, the only situation where it does this is when it can't do a 3-way
merge at all because it can't find the necessary ancestor blob. This can only
happen if you transfer a patch between different repos that don't have the
same blobs available; we are applying the patch to the same repo that is was
just generated from, so a 3-way merge is always possible. (Now that we fixed
the bug in the previous commit, that is.)
But the retry loop is not only pointless, it was actually harmful, because when
a 3-way patch fails with a conflict, git will put conflict markers in the
patched file and then exit with a non-zero exit status. So the retry loop would
try to patch the already patched file again, and this almost certainly fails,
but with a cryptic error message such as "error: main.go: does not exist in
index".
There's no reason to have two different ways of applying patches for whole-file
patches and partial patches; use --reverse for both. Not only does this simplify
the code a bit, but it fixes an actual problem: when reverseOnGenerate and
keepOriginalHeader are both true, the generated patch header is broken (the two
blobs in the line `index 6d1959b..6dc5f84 100644` are swapped). Git fails to do
a proper three-way merge in that case, as it expects the first of the two blobs
to be the common ancestor.
It would be possible to fix this by extending ModifiedPatchForLines to swap the
two blobs in this case; but this would prevent us from concatenating all patches
and apply them in one go, which we are going to do later in the branch.
We are going to add one more flag in the next commit.
Note that we are not using the struct inside patch_manager.go; we keep passing
the individual flags there. The reason for this will become more obvious later
in this branch.
Instead, derive it from context at display time (if we're rebasing, it's the
first non-todo commit). This fixes the problem that unfolding the current
commit's files in the local commits panel would show junk in the frame's title.
Along the way we make sure to only display the "<--- YOU ARE HERE" string in the
local commits panel; previously it would show for the top commit of a branch or
tag if mid-rebase.