Exploring Cursor/Windsurf/Copilot: Reducing Friction for Version Control


This chapter is taken from my book, "AI Assisted Coding for iOS Development". You can buy it to learn further about Cursor:

Exploring AI Assisted Coding
Cursor, Copilot, Windsurf, Alex for iOS Development

I have been using Sourcetree (no affiliation) for over five years. It has become second nature to me. I tried Xcode’s version control with custom keyboard shortcuts, but old habits die hard, and I returned to Sourcetree.

Nothing is wrong with that, but I prefer to commit more frequently when working with tools like Cursor’s Composer, Windsurf, or GitHub’s Copilot. If something goes wrong, I can quickly revert to a previous state.

In Cursor’s Composer, you can use the “Save All” function instead of accepting changes, but I want a long-term solution. So, let’s explore how you can use version control with custom keyboard shortcuts to reduce the friction of committing your changes. We will also look into using the LLMs to write commit messages based on the changes made since the last commit.

Keyboard Shortcuts for Version Control

The flow for me right now is making some changes in Cursor, making sure it works, switching to Sourcetree, selecting and staging the files to commit (which are mostly all of them), writing a commit message, and merging in the current branch.

I want to see how to reduce friction and use keyboard shortcuts in the IDE to perform the above flow.

Both Cursor and Windsurf are based on Visual Studio Code, so the following commands should work regardless of the IDE you use.

Use the Shift + Control + G keyboard shortcut to open the source control navigator. It (sometimes) automatically focuses the cursor (pun intended) on the commit message text field so you can start typing the message, or it will focus on the first staged/unstaged file.

I prefer to create the keyboard bindings in JSON to stage all changes. You can open the command palette using Shift + Command + P and then type Preferences: Open Keyboard Shortcut (JSON) to access the JSON configuration. Then, add the following:

[
  {
    "key": "shift+alt+cmd+s",
    "command": "git.stageAll"
  }
]

To go all in, I can directly use the option that pulls, commits the message, and pushes it to the repository using git.sync:

[
  {
    "key": "shift+ctrl+p",
    "command": "git.sync"
  }
]

Be careful when using this, especially in a team context, to avoid merge conflicts.

There are many keyboard shortcuts that you can explore, like the following that chains the command for staging the changes, committing, and pushing:

{
  "key": "cmd+ctrl+k",
  "command": "runCommands",
  "args": {
    "commands": [
      {
        "command": "git.stageAll"
      },
      {
        "command": "git.commit"
      },
      {
        "command": "git.push"
      }
    ]
  },
  "when": "editorTextFocus"
}

Using AI to Generate Commit Messages

If I look at the commit messages of my open-source projects, I realize that I am lazier than I thought.

"Fix" is not a commit message, Rudrank.

It can get time-consuming. So, I used this laziness to my advantage to find ways to have the LLMs write the message for me.

GitHub Copilot

GitHub Copilot in VS Code has a button to generate commit messages summarizing the changes:

github.copilot.git.generateCommitMessage

We can add it to the custom keyboard shortcuts configuration in a similar way that we did before. For example, to bind it to Command + Option + G, you could add this:

// Place your key bindings in this file to override the defaults
[
    {
        "key": "cmd+alt+g",
        "command": "runCommands",
        "args": {
          "commands": [
            {
              "command": "git.stageAll"
            },
            {
              "command": "github.copilot.git.generateCommitMessage"
            },
            {
              "command": "git.commit"
            },
            {
              "command": "git.push"
            }
          ]
        },
        "when": "editorTextFocus"
      }
]

Here is what this does:

  • Stage All Changes: Quickly stage everything modified.
  • Generate Commit Message: Summarize the diff using Copilot.
  • Commit Changes: Commit with the AI-generated message.
  • Push to Remote: Push the changes to the repository.

With this setup, you can commit and push in a single keystroke with a meaningful message.

Cursor

Update 0.43.5: Cursor now has similar a Generate Commit Message option like Copilot, and you can use it similarly to bind it to a keyboard shortcut:

[
    {
        "key": "cmd+alt+g",
        "command": "runCommands",
        "args": {
          "commands": [
            {
              "command": "git.stageAll"
            },
            {
              "command": "cursor.generateGitCommitMessage"
            },
            {
              "command": "git.commit"
            },
            {
              "command": "git.push"
            }
          ]
        },
        "when": "editorTextFocus"
      }
]

In Cursor, you can use @Commit to fetch the changes and then have a chat to generate the commit message:

@Commit (Diff of Working State) Generate commit message

In my case, it gave a good commit message that I would have never written myself:

Replace Inject with HotSwiftUI for hot reloading

- Remove Inject package dependency and related imports
- Add HotSwiftUI package for hot reloading functionality
- Update hot reload implementation across views
- Fix platform-specific compilation in FeatureCraftView
- Bump version to 1.2.1

Moving Forward

While I mostly work independently, clear commit messages are critical for team projects. Review the AI-suggested messages if you are using Cursor’s @Commit or Copilot’s commit generation. Sometimes, they do the job; other times, they may miss the context your teammates need.

Happy cursoring!