Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: Move git commands from deferred code into functions #343

Closed
wants to merge 3 commits into from

Conversation

sandr01d
Copy link
Collaborator

@sandr01d sandr01d commented Feb 2, 2024

Check list

  • I have performed a self-review of my code
  • I have commented my code in hard-to-understand areas
  • I have made corresponding changes to the documentation

Description

We often used deferred code to encapsulate git commands and make them reusable. This change removes deferred code for git commands and replaces it with functions instead.
Some of these new functions are used with xargs, which needs to execute them from a subshell. To make this possible, we now expose the concerned functions as forgit commands without advertising them in the help text.

Type of change

  • Bug fix
  • New feature
  • Refactor
  • Breaking change
  • Documentation change

Test environment

  • Shell
    • bash
    • zsh
    • fish
  • OS
    • Linux
    • Mac OS X
    • Windows
    • Others:

Note

This PR belongs to #326 and resulted from discussions in #324

Forgit allows specifying git options in environment variables that are passed along to the individual git commands. We currently treat those as strings. This commit adds a _forgit_parse_array function and uses it to parse all such environment variables into arrays instead. This will allow us to get rid of deferred code, since we can pass the parsed arrays directly to the git commands and don't have to rely on eval.
@sandr01d
Copy link
Collaborator Author

sandr01d commented Feb 2, 2024

@carlfriedrich I did not include the deferred git commands that we did not end up creating functions for in this PR. Let me know whether you would like to have them included here.

A note regarding 2d81ed9: This was not originally included in #326. When I was revisiting this I came to the conclusion that a _forgit_git_branch_delete function should always pass the -D flag to git branch.

Copy link
Collaborator

@carlfriedrich carlfriedrich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sandr01d Thanks a lot for submitting this new patch!

Haven't looked into everything in detail, yet, but first thing I noticed is that 7657444 reverts some of the changes of #338. The array parsing in the functions gets lost. Can you fix that?

@sandr01d
Copy link
Collaborator Author

sandr01d commented Feb 3, 2024

Haven't looked into everything in detail, yet, but first thing I noticed is that 7657444 reverts some of the changes of #338. The array parsing in the functions gets lost. Can you fix that?

The array parsing was moved into the _forgit_git_* functions were the arrays are being used. I think it is correct as is, can you verify?

@carlfriedrich
Copy link
Collaborator

@sandr01d Yes, they are correctly added in the first commit of this PR (1e8f79e), but the second commit (7657444) removes the calls from the _forgit_git_* functions again.

@sandr01d
Copy link
Collaborator Author

sandr01d commented Feb 3, 2024

@sandr01d Yes, they are correctly added in the first commit of this PR (1e8f79e), but the second commit (7657444) removes the calls from the _forgit_git_* functions again.

Could you please point me to a line were this is happening, I do not understand. The parsing is added to the _forgit_* functions in 1e8f79e and moved to the _forgit_git_* functions in 7657444. See for example, _git_forgit_add after 7657444:

https://github.com/sandr01d/forgit/blob/2d81ed909fd799566fb7c377f09e6b23a2675173/bin/git-forgit#L183C1-L187C2

@carlfriedrich
Copy link
Collaborator

@sandr01d Oh, I'm sorry! I viewed the patch on my tiny mobile phone screen, which obviously is not a good idea, and also I obviously did not read your comment correctly. 🙈 So yes, on my desktop monitor I see now that the calls are moved and not removed. Will have a more detailed look soon.

@sandr01d
Copy link
Collaborator Author

sandr01d commented Feb 3, 2024

@sandr01d Oh, I'm sorry! I viewed the patch on my tiny mobile phone screen, which obviously is not a good idea, and also I obviously did not read your comment correctly. 🙈 So yes, on my desktop monitor I see now that the calls are moved and not removed. Will have a more detailed look soon.

No worries and thanks for the clarification. I was only questioning my sanity for a brief second 😆

@carlfriedrich
Copy link
Collaborator

Just browsed through all the changes and the patch looks clean, great work! Also good catch with the -D flag in _forgit_git_branch_delete. I would suggest to squash that commit into its parent.

I wonder if we could replace the four xargs calls with for loops, so that we do not have to export these git functions as private functions to the forgit CLI. That would make the code more readable IMO, because we would remove a level of indirection there and call the functions directly. WDYT?

@sandr01d
Copy link
Collaborator Author

sandr01d commented Feb 3, 2024

I would suggest to squash that commit into its parent.

Done

I wonder if we could replace the four xargs calls with for loops, so that we do not have to export these git functions as private functions to the forgit CLI. That would make the code more readable IMO, because we would remove a level of indirection there and call the functions directly. WDYT?

I think that is a great idea, but I think we should probably do so in a follow up PR once #326 has been merged. I see this as more of a general refactor and not related to deferred code and #326 is already pretty big. WDYT?
Also implementing it in this PR is rather difficult for _forgit_stash_show, since xargs is currently being used in deferred code, that is replaced with _forgit_stash_show_preview later in #326. So replacing it later would be way easier.

@carlfriedrich
Copy link
Collaborator

I understand that this can be seen as a more general refactoring. I think, though, that it would make this specific commit better, so IMO it would be the right thing to do here.
Concerning the complexity of this PR, it would add the xargs refactoring, but instead remove the introduction of private_commands here, so I think this specific PR wouldn't grow in complexity.
And concerning the complexity of #326: everything we extract to these chunk-PRs will reduce the overall complexity of the final PR (what we're doing here doesn't need to be done in #326).
I see, however, that everything we're adding here which wasn't part of #326 before, increases the difficulty of rebasing #326 on this PR. I would consider this a good invest, though, and I again want to offer my help with this. I know, rebasing can be a pain, but I still enjoy doing it when I know that it's worth for a good end result.
So are you in? 🤗

@sandr01d
Copy link
Collaborator Author

sandr01d commented Feb 4, 2024

I understand that this can be seen as a more general refactoring. I think, though, that it would make this specific commit better, so IMO it would be the right thing to do here.

That is totally reasonable and I agree with that. I am not against the change, but I don't really see a good way to implement it in this specific PR, let me elaborate a bit on this.
I've refactored _forgit_reset_head, _forgit_checkout_commit and _forgit_branch_delete and they work fine. You can take a look at it here in case you're interested.
The issue is with _forgit_stash_show. The usage of xargs is withing deferred code that is executed from an fzf subshell:

# xargs is within this deferred code
cmd="echo {} |cut -d: -f1 |xargs -I% $FORGIT git_stash_show % |$_forgit_diff_pager"
    opts="
        $FORGIT_FZF_DEFAULT_OPTS
        +s +m -0 --tiebreak=index --bind=\"enter:execute($cmd | $_forgit_enter_pager)\"
        --bind=\"ctrl-y:execute-silent(echo {} | cut -d: -f1 | tr -d '[:space:]' | ${FORGIT_COPY_CMD:-pbcopy})\"
# we use this for the fzf preview here
        --preview=\"$cmd\"
        $FORGIT_STASH_FZF_OPTS
    "

We can not call _forgit_git_stash_show from the subshell. We've introduced the private_commands to deal with this particular issue for the _forgit_*_preview functions. The code I've pasted above is later on replaced with a preview function and then it becomes trivial to get rid of xargs:

_forgit_stash_show_preview() {
-   echo "$1" | cut -d: -f1 | xargs -I% "$FORGIT" "git_stash_show" % | $_forgit_diff_pager
+   # we don't actually need a loop here because
+   # there is always just one stash previewed
+   local stash
+   stash=$(echo "$1" | cut -d: -f1)
+   _forgit_git_stash_show "$stash" | $_forgit_diff_pager
}

If we want to get rid of xargs and the private_commands in this PR that means we'd have to find a new solution to this. Which to me clearly indicates that we should isolate other chunks first and once the _forgit_*_preview functions are introduced, we could rebase this PR on top of that.

I see, however, that everything we're adding here which wasn't part of #326 before, increases the difficulty of rebasing #326 on this PR. I would consider this a good invest, though, and I again want to offer my help with this.

Appreciated, thanks. I think it would be great if we could take turns rebasing every now and then. 👍

@carlfriedrich
Copy link
Collaborator

@sandr01d Ah, I see. Thanks for the detailed explanation. I actually didn't realize that it's used in deferred code at one place. In this case I agree, let's do this after #326. I'd consider this PR approved then. ✅

Shall I rebase #326 on this PR then?

@sandr01d
Copy link
Collaborator Author

sandr01d commented Feb 4, 2024

Alternatively, to doing this after #326, we could keep this here as is for the moment and continue splitting out other chunks. Once the preview functions are introduced, we can rebase this PR on top of that and get rid of xargs here. I would convert this PR in a draft in this case. I think that would result in the cleanest commit history, so what do you think about that?

@carlfriedrich
Copy link
Collaborator

That sounds like a good idea! Then let's do the preview functions in the next chunk. I just took a quick look over them and think they would make a reasonable patch. WDYT?

Removes the deferred code that is used for creating the fzf preview functions and replaces it with _forgit_*_preview functions instead. These functions are exposed as forgit commands so they can be invoked from the fzf subshell. We split the exposed commands into public_commands and private_commands. The only difference between them is that public_commands are mentioned in the help text.
This commit changes the flags variable in _forgit_blame from a string to an array. This is necessary to allow the flags to be passed to _forgit_blame_preview as individual arguments.
@sandr01d sandr01d marked this pull request as ready for review February 18, 2024 17:46
@sandr01d
Copy link
Collaborator Author

sandr01d commented Feb 18, 2024

I've now rebased this PR on #349 and replaced the usage of xargs, as previously requested by @carlfriedrich. Re-requesting you reviews @cjappl @carlfriedrich.
There is one thing that I did not mention before, that I'd like to discuss with you. This PR does not replace all deferred git commands in all our main functions. It only replaces the occurrences that we introduced new functions for in #326. In some places this was not necessary, due to the git command only being used a single time, e.g. in _forgit_cherry_pick and _forgit_clean. I could include the code changes that remove the deferred code there here as well if you prefer.

Copy link
Collaborator

@carlfriedrich carlfriedrich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks mostly good to me, thanks for the work. Can you check the two comments I left?

bin/git-forgit Show resolved Hide resolved
@@ -677,9 +709,15 @@ _forgit_branch_delete() {
"

cmd="git branch --color=always | LC_ALL=C sort -k1.1,1.1 -rs"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about this deferred git call here? Can we get rid of that as well?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've only included deferred git calls that we replaced with separate functions in #326, see my previous comment. We could replace all deferred git calls in this PR, which would make it a bit bigger, as there are still a few of them left that we did not create functions for. We could also do that in the next PR. I'm open for both.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry, I missed that part of the comment in the first place. I would prefer replacing all git calls in this PR, since that's what its title says. :-)

Copy link
Collaborator Author

@sandr01d sandr01d Feb 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0de4f2e removes all deferred git commands. I had to include converting $_forgit_emojify into a function and the replacement of the $graph variable with an array to get the commands working without deferred code and eval. This makes this PR quite big. Haven't squashed the commit yet, because I'm thinking creating a separate PR out of 0de4f2e to reduce the size of this one. WDYT?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see, that's quite a huge additional change indeed. I did not expect that, sorry. So yes, let's move that to a new PR. I would consider this PR finished then.

Do I get it right that none of the new changes were part of the original #326? I wonder what's the best way to continue then, since we have some changes in #326 left to include. Shall we do those first?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I get it right that none of the new changes were part of the original #326?

No they were mostly part of #326, I just moved them over to this branch. The only thing in this PR that is not in #326 yet are the four hunks that remove xargs.
I would suggest we rebase #326 on this PR to make sure we don't digress too far and I create a new PR that converts $_forgit_emojify into a function and after that a PR that replaces the rest of the deferred git commands. Sounds good?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that sounds good, thanks a lot!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: I started to rebase #326. I'm almost done and will finalize it tomorrow, so don't put any effort into it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wow, thanks a lot for your effort!

Copy link
Owner

@wfxr wfxr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Collaborator

@cjappl cjappl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did a functional check with fish on MacOS and seems like everything is still working as intended :)

@sandr01d sandr01d force-pushed the git-functions branch 3 times, most recently from 9659072 to 84acaf2 Compare February 21, 2024 21:10
We often used deferred code to encapsulate git commands and make them
reusable.
This change removes deferred code for git commands and replaces it with
functions instead.
Some of the deferred code was used with xargs, which executes it on a
subshell. To avoid having to expose the new git functions the same way
we do with the preview functions, the usage of xargs in these cases is
replaced with either a loop or a single command when possible.
@sandr01d
Copy link
Collaborator Author

Changes have been merged with #326

@sandr01d sandr01d closed this Mar 24, 2024
@sandr01d sandr01d deleted the git-functions branch April 5, 2024 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants