drewdeponte / git-ps-rs

Official git-ps Rust implementation - the future of git-ps
https://git-ps.sh
MIT License
78 stars 8 forks source link

Add in middle of rebase support to the `gps list` command #273

Closed drewdeponte closed 9 months ago

drewdeponte commented 10 months ago

The idea with this is that when you are in the middle of a rebase because of either interactive or because of a conflict, or what not. gps list will still work and it will actually show you visually the state you are in in the current patch stack.

This means it should show you the commits that have already been rebased along with their associated branch associations and statuses as normal.

But then it should have some sort of separation above it (maybe just a blank line or something) and then have the commits that are to be replayed when when you run a git rebase --continue. These commits should also have associated branches and state info like gps list currently shows.

drewdeponte commented 10 months ago

libgit2 doesn't currently support opening interactive rebases. So what I am thinking about doing is implementing my own light weight functionality to read the necessary data from the .git directory in pure Rust.

From poking around a bit it looks like when you are in the middle of a rebase a .git/rebase-merge directory exists. The insides of this directory consists of something like the following.

✔ ls -l .git/rebase-merge                                                                                                               33589m  939efeb+rebase
total 104
-rw-r--r--@ 1 drewdeponte  staff    41 Nov 12 14:42 amend
-rw-r--r--@ 1 drewdeponte  staff   107 Nov 12 14:42 author-script
-rw-r--r--@ 1 drewdeponte  staff   264 Nov 12 14:42 done
-rw-r--r--@ 1 drewdeponte  staff     2 Nov 12 14:42 end
-rw-r--r--@ 1 drewdeponte  staff   136 Nov 12 14:42 git-rebase-todo
-rw-r--r--@ 1 drewdeponte  staff  1881 Nov 12 14:42 git-rebase-todo.backup
-rw-r--r--@ 1 drewdeponte  staff     3 Nov 12 14:42 gpg_sign_opt
-rw-r--r--@ 1 drewdeponte  staff    16 Nov 12 14:42 head-name
-rw-r--r--@ 1 drewdeponte  staff     0 Nov 12 14:42 interactive
-rw-r--r--@ 1 drewdeponte  staff    77 Nov 12 14:42 message
-rw-r--r--@ 1 drewdeponte  staff     2 Nov 12 14:42 msgnum
-rw-r--r--@ 1 drewdeponte  staff     0 Nov 12 14:42 no-reschedule-failed-exec
-rw-r--r--@ 1 drewdeponte  staff    41 Nov 12 14:42 onto
-rw-r--r--@ 1 drewdeponte  staff    41 Nov 12 14:42 orig-head
-rw-r--r--@ 1 drewdeponte  staff     0 Nov 12 14:42 patch
-rw-r--r--@ 1 drewdeponte  staff    41 Nov 12 14:42 stopped-sha

At least that is true when I tested doing an interactive rebase where I flagged a commit in the middle for edit.

It seems that the existance or lack of existance of the interactive file is probably used to indicate interactive vs non-interactive rebase.

The head-name file holds the reference that is being rebased.

✔ cat .git/rebase-merge/head-name                                                                                                       33593m  939efeb+rebase
refs/heads/main

The done file seems to hold the commits that have already been replayed.

✔ cat .git/rebase-merge/done                                                                                                            33602m  939efeb+rebase
pick 7a645dbc60057ef469b9a2bc4a82b30fa5efbb75 Free world
pick a403343e8a173dc8cc2fa27d9465b13fe2c0d627 Free new world
pick 54fd6c2a52eaf0d67eaea5adc289c0831f5f4f7e Add comment to the end
edit 939efeb6a58842e931ed0277686c9d899b2671ae Add comment to the end # empty

The end file seems to hold an integer representing the number of commits to be replayed in total.

✔ cat .git/rebase-merge/end                                                                                                             33603m  939efeb+rebase
6

The git-rebase-todo file seems to hold the commits that still need to be replayed

✔ cat .git/rebase-merge/git-rebase-todo                                                                                                 33604m  939efeb+rebase
pick acd3e52e0eab5c6239e5b183ca10f3f2e4ec94d6 Merge branch 'foo' # empty
pick 6346a1c22019bf1e4ca69e11816a4217cf490f48 Test gpg signing

The message file seems to hold the commit message for the commit that is flagged for edit.

✔ cat .git/rebase-merge/message                                                                                                         33605m  939efeb+rebase
Add comment to the end

<!-- ps-id: e214d699-8116-4f47-a65e-ef45547e3f9b -->

The msgnum file seems to hold in integer represnting the index of the commit it is editing, assuming it is 0 indexed.

✔ cat .git/rebase-merge/msgnum                                                                                                          33606m  939efeb+rebase
4

The onto file seems to hold the sha of the commit to replay the entire series of commits onto.

✔ cat .git/rebase-merge/onto                                                                                                            33608m  939efeb+rebase
66862a013d670570e6038f65241f16c83282b2d5

The orig-head file seems to hold the sha of the commit that was originally the head of the branch being rebased, prior to rebasing.

✔ cat .git/rebase-merge/orig-head                                                                                                       33609m  939efeb+rebase
6346a1c22019bf1e4ca69e11816a4217cf490f48

The stopped-sha file seems to contain the sha of the commit that the intercative rebase stopped at for editing.

✔ cat .git/rebase-merge/stopped-sha                                                                                                     33612m  939efeb+rebase
939efeb6a58842e931ed0277686c9d899b2671ae

I am not sure what the patch file indicates exactly, but it is empty. So maybe the existance or non existance of it indicates something.

The gpg_sign_opt seems to contain the gpg signing option. I assume based on either the config or command line options.

✔ cat .git/rebase-merge/gpg_sign_opt                                                                                                    33613m  939efeb+rebase
-S

I am not sure what the amend file is for, but it seems to contain the sha of the commit that was flagged for editing and we are currently stopped at in the rebase.

✔ cat .git/rebase-merge/amend                                                                                                           33614m  939efeb+rebase
939efeb6a58842e931ed0277686c9d899b2671ae

The author-script seems to contain some sort of script to set the author name, email, and date I would assume for the replaying of the commits.

✔ cat .git/rebase-merge/author-script                                                                                                   33616m  939efeb+rebase
GIT_AUTHOR_NAME='Drew De Ponte'
GIT_AUTHOR_EMAIL='cyphactor@gmail.com'
GIT_AUTHOR_DATE='@1697829045 -0400'

The git-rebase-todo.backup file seems to contain the original todo from the interactive rebase prior to me marking the commit for edit and saving and quiting.

✔ cat .git/rebase-merge/git-rebase-todo.backup                                                                                          33617m  939efeb+rebase
pick 7a645dbc60057ef469b9a2bc4a82b30fa5efbb75 Free world
pick a403343e8a173dc8cc2fa27d9465b13fe2c0d627 Free new world
pick 54fd6c2a52eaf0d67eaea5adc289c0831f5f4f7e Add comment to the end
pick 939efeb6a58842e931ed0277686c9d899b2671ae Add comment to the end # empty
pick acd3e52e0eab5c6239e5b183ca10f3f2e4ec94d6 Merge branch 'foo' # empty
pick 6346a1c22019bf1e4ca69e11816a4217cf490f48 Test gpg signing

# Rebase 66862a0..6346a1c onto 66862a0 (6 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
#                    commit's log message, unless -C is used, in which case
#                    keep only this commit's message; -c is same as -C but
#                    opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
#         create a merge commit using the original merge commit's
#         message (or the oneline, if no original merge commit was
#         specified); use -c <commit> to reword the commit message
# u, update-ref <ref> = track a placeholder for the <ref> to be updated
#                       to this position in the new commits. The <ref> is
#                       updated at the end of the rebase
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#

I am not sure what the no-reschedule-failed-exec file is for exactly. But it is empty. So maybe the existance or non existance of it means something. Not sure.

drewdeponte commented 10 months ago

Ok, I think the functionality we basically need is as follows.

It is worth noting that the last two seem to be the same file format. Therefore, it is probably just worth implementing a parser for that file format.

I believe with that information we should be able to modify the gps list command to actually work in the middle of a rebase.

drewdeponte commented 9 months ago

I have a patch locally that implements a spike of it. The todo parser currently only addresses commands that operate on individual sha.

Next up I need to expand the parser to support parsing all the different command variants in the todo files so that we don't have any edge case problems. Also it will allow us to present the various commands in different ways if we decide it makes sense.

drewdeponte commented 9 months ago

This has been integrated into mainline. Therefore, I am closing this issue.