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

feat(switch): accept revset arguments, and explicitly support - shorthand #1463

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

claytonrcarter
Copy link
Collaborator

@claytonrcarter claytonrcarter commented Dec 8, 2024

This updated git switch to accept a revset as it's argument, and also to support - (to checkout previously checked out branch/commit) by passing it through to git.

The revset parameter must evaluate to a set with a single head, and I've found this handy in cases like current(...) to move to the latest version of a commit if I had an old smartlog or SHA still on screen or such, and also switch foo: for when I have a branch ref handy but I really want to checkout the latest detached commit in that stack.

But with revset support added, switch - broke because it looked a poorly formed revset:

Message:  A fatal error occurred:
   0: parse error in "-": parse error: Unrecognized token `-` found at 0:1
      Expected one of "(", "..", ":", "::", a commit/branch/tag or a string literal
   1: parse error: Unrecognized token `-` found at 0:1
      Expected one of "(", "..", ":", "::", a commit/branch/tag or a string literal

The last commit in this stack adds an explicit check for - so that this support is restored.

Apparently, revparse_single() in libgit2 doesn't support this. ~~I didn't patch - support into repo.revparse_single_commit() but I'm thinking as I write this that perhaps that may be better? There is already a special case in that function to work around another libgit2 issue, and I suppose we could detect if the passed spec is - and then pass @{-1} to revparse_single() instead. 🤔 ~~ edit I made this change and it seems to be working.

@claytonrcarter claytonrcarter force-pushed the switch-revset branch 3 times, most recently from 5cc1b7a to df58ccf Compare December 10, 2024 16:11
Copy link
Owner

@arxanas arxanas left a comment

Choose a reason for hiding this comment

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

Thanks! Both of these issues have bothered me personally as well.

@@ -512,16 +512,22 @@ pub fn switch(

enum Target {
Interactive(String),
Revision(String),
Copy link
Owner

Choose a reason for hiding this comment

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

issue: I think it's misleading to call this Revision, because it sounds like it's meant to refer to a revision/commit specifically, and not be a general revision specification, which can indicate a branch.

Some ideas for renaming it:

  • Revspec (but I'm not sure if this is legitimate Git terminology)
  • RevisionOrRef
  • RevparseSingleCommit
  • Uninterpreted or similar
    • I guess it would be better if CheckoutTarget::Unknown were actually named CheckoutTarget::Uninterpreted or similar, since Unknown is kind of weird to say when the value is clearly known.

Let's also add a comment to this enum case explaining that it can also represent branches, etc.


match commits.as_slice() {
[commit] => Some(CheckoutTarget::Unknown(commit.get_oid().to_string())),
[] => None,
Copy link
Owner

Choose a reason for hiding this comment

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

question: Is it intentional for you that having a revset that resolves to the empty set should do nothing? I could imagine it being useful for some workflow, although I don't have one in mind.

issue: Technically speaking, isn't the stated specification that the set must have exactly 1 head not correct?

[..] => {
writeln!(
effects.get_error_stream(),
"Cannot switch to target: expected '{target}' to contain 1 head, but found {}.",
Copy link
Owner

Choose a reason for hiding this comment

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

comment (non-blocking): In principle we could list all of the candidate targets, which we also do when git next or git prev is ambiguous, but it's not necessary to implement that here.


{
// switching back to "last checkout"
let (stdout, _stderr) = git.branchless("switch", &["-"])?;
Copy link
Owner

Choose a reason for hiding this comment

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

suggestion: Can you add a test to ensure that git switch - is also capable of checking out the previous branch, not just the previous commit? (I believe that's how it works in Git.)

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.

2 participants