Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 0 additions & 19 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,3 @@ jobs:
run: npm run test
- name: Run packaging smoke test
run: npx @vscode/vsce package

old-version-support:
runs-on: ubuntu-latest
steps:
- name: Install Git 2.25.1
run: |
echo "deb http://archive.ubuntu.com/ubuntu focal-updates main universe" | sudo tee /etc/apt/sources.list.d/focal.list
sudo apt-get update
sudo apt-get install --allow-downgrades -y git=1:2.25.1-1ubuntu3.13 git-man=1:2.25.1-1ubuntu3.13
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Run unit tests
run: npm run test
22 changes: 21 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,16 @@
"vscode": "^1.96.0"
},
"main": "./out/extension.js",
"enabledApiProposals": ["contribSourceControlHistoryItemMenu"],
"contributes": {
"commands": [
{
"command": "git-fixup.amendStagedChanges",
"title": "Git Fixup: Amend Staged Changes"
},
{
"command": "git-fixup.amendStagedChangesToHistoryItem",
"title": "Amend Staged Changes"
Copy link

Choose a reason for hiding this comment

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

Any chance to tweak this to Amend Staged Changes ("Fixup")

}
],
"keybindings": [
Expand All @@ -32,7 +37,22 @@
"mac": "cmd+alt+shift+f",
"when": "editorTextFocus"
}
]
],
"menus": {
"scm/historyItem/context": [
{
"command": "git-fixup.amendStagedChangesToHistoryItem",
"when": "scmProvider == git",
"group": "1_actions"
}
],
"commandPalette": [
{
"command": "git-fixup.amendStagedChangesToHistoryItem",
"when": "false"
}
]
}
},
"scripts": {
"vscode:prepublish": "npm run compile",
Expand Down
9 changes: 9 additions & 0 deletions src/GitFacade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,20 @@ export class GitFacade {
}
}

async isCommitInUptream(hash: string): Promise<boolean> {
const result = await this.git.raw(['branch', '-r', '--contains', hash])
return (result.trim() !== '')
}

async getLatestFixedCommit(): Promise<Commit> {
// old Git versions (earlier than v2.26) include "-i" in the message
return (await this.queryCommits('--grep-reflog=rebase (fixup)', '--grep-reflog=rebase -i (fixup)', '--walk-reflogs', '-1'))[0]
}

async getCommit(hash: string): Promise<Commit> {
return (await this.queryCommits(hash, '-1'))[0]
}

private async queryCommits(...args: string[]): Promise<Commit[]> {
const lines = toLines(await this.git.raw(['log', ...args, '--format=%h %s']))
return lines.map((line) => {
Expand Down
64 changes: 46 additions & 18 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as vscode from 'vscode'
import { GitFacade, NO_UPSTREAM } from './GitFacade'
import { Commit } from './types'

export const activate = (context: vscode.ExtensionContext): void => {

Expand Down Expand Up @@ -29,6 +30,26 @@ export const activate = (context: vscode.ExtensionContext): void => {
}
}

const amendStagedChangesToCommit = async (selectedCommit: Commit & { isInUpstream: boolean }) => {
if (selectedCommit.isInUpstream) {
const confirm = await vscode.window.showInformationMessage('The commit has been pushed to the upstream. Do you want to proceed?', 'Yes', 'No')
if (confirm !== 'Yes') {
return
}
}
await git.commitFixup(selectedCommit.hash)
const isMergeConflict = await git.rebaseFixupCommit(selectedCommit.hash)
if (isMergeConflict) {
writeToOutputChannel(`Merge conflict while fixing ${selectedCommit.hash}`)
vscode.window.showErrorMessage('Merge conflict\n\nResolve the conflict manually, then use Git: Commit (Amend) to commit the changes.\n', { modal: true })
return
}
const fixedCommit = await git.getLatestFixedCommit()
const successMessage = `Fixed: ${selectedCommit.hash}->${fixedCommit.hash} - ${selectedCommit.subject}`
writeToOutputChannel(successMessage)
vscode.window.showInformationMessage(successMessage)
}

const disposable = vscode.commands.registerCommand('git-fixup.amendStagedChanges', async () => {

try {
Expand Down Expand Up @@ -66,35 +87,42 @@ export const activate = (context: vscode.ExtensionContext): void => {
iconPath: getCommitIcon(isInUpstream, isHighlighted),
label: ` ${messageSubject}`,
hash: commit.hash,
messageSubject,
subject: commit.subject,
isInUpstream
}
})))
const selectedCommit = await vscode.window.showQuickPick(commitChoices, { placeHolder: 'Select a Git commit to fix up' })

if (selectedCommit !== undefined) {
if (selectedCommit.isInUpstream) {
const confirm = await vscode.window.showInformationMessage('The commit has been pushed to the upstream. Do you want to proceed?', 'Yes', 'No')
if (confirm !== 'Yes') {
return
}
}
await git.commitFixup(selectedCommit.hash)
const isMergeConflict = await git.rebaseFixupCommit(selectedCommit.hash)
if (isMergeConflict) {
writeToOutputChannel(`Merge conflict while fixing ${selectedCommit.hash}`)
vscode.window.showErrorMessage('Merge conflict\n\nResolve the conflict manually, then use Git: Commit (Amend) to commit the changes.\n', { modal: true })
return
}
const fixedCommit = await git.getLatestFixedCommit()
const successMessage = `Fixed: ${selectedCommit.hash}->${fixedCommit.hash} - ${selectedCommit.messageSubject}`
writeToOutputChannel(successMessage)
vscode.window.showInformationMessage(successMessage)
await amendStagedChangesToCommit(selectedCommit)
}
} catch (error) {
vscode.window.showErrorMessage(error.message)
}
})

context.subscriptions.push(disposable, outputChannel)

context.subscriptions.push(
// TODO explicit types for the arguments (most likely 1st is ISCMProvider and 2nd is ISCMHistoryItem)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
vscode.commands.registerCommand('git-fixup.amendStagedChangesToHistoryItem', async (_: any, historyItem: any) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
git.updateWorkingDirectory(vscode.workspace.workspaceFolders![0]!.uri.fsPath)
const stagedFiles = await git.getStagedFiles()
if (stagedFiles.length === 0) {
vscode.window.showErrorMessage('No staged files')
return
}
const hash = historyItem.id
try {
const commit = await git.getCommit(hash)
const isInUpstream = await git.isCommitInUptream(hash)
await amendStagedChangesToCommit({ ...commit, isInUpstream })
} catch (error) {
vscode.window.showErrorMessage(error.message)
}
}),
outputChannel
)
}
Loading