diff --git a/packages/ui/src/components/views/GitView.tsx b/packages/ui/src/components/views/GitView.tsx index 6b90930a..a5dcfc66 100644 --- a/packages/ui/src/components/views/GitView.tsx +++ b/packages/ui/src/components/views/GitView.tsx @@ -948,6 +948,8 @@ export const GitView: React.FC = () => { if (!remote) { throw new Error('No remote available for sync'); } + let pulledFileCount = 0; + let pushedChanges = false; await git.gitFetch(currentDirectory, { remote: remote.name }); const afterFetch = await git.getGitStatus(currentDirectory); @@ -956,14 +958,32 @@ export const GitView: React.FC = () => { toast.error(t('gitView.toast.commitOrStashBeforeSync')); return; } - await git.gitPull(currentDirectory, getPullOptions(remote)); + const pullResult = await git.gitPull(currentDirectory, getPullOptions(remote)); + pulledFileCount = pullResult.files.length; } const afterPull = await git.getGitStatus(currentDirectory); if ((afterPull.ahead ?? 0) > 0) { await git.gitPush(currentDirectory); + pushedChanges = true; + } + if (pulledFileCount > 0 && pushedChanges) { + toast.success( + pulledFileCount === 1 + ? t('gitView.toast.syncedPulledSingleAndPushed', { count: pulledFileCount, name: remote.name }) + : t('gitView.toast.syncedPulledPluralAndPushed', { count: pulledFileCount, name: remote.name }) + ); + } else if (pulledFileCount > 0) { + toast.success( + pulledFileCount === 1 + ? t('gitView.toast.pulledFilesSingle', { count: pulledFileCount, name: remote.name }) + : t('gitView.toast.pulledFilesPlural', { count: pulledFileCount, name: remote.name }) + ); + } else if (pushedChanges) { + toast.success(t('gitView.toast.pushedToUpstream')); + } else { + toast.success(t('gitView.toast.syncedChanges')); } - toast.success(t('gitView.toast.syncedChanges')); } await refreshStatusAndBranches(false); diff --git a/packages/ui/src/components/views/git/SyncActions.tsx b/packages/ui/src/components/views/git/SyncActions.tsx index f32de47a..790bef9d 100644 --- a/packages/ui/src/components/views/git/SyncActions.tsx +++ b/packages/ui/src/components/views/git/SyncActions.tsx @@ -54,11 +54,16 @@ export const SyncActions: React.FC = ({ const blocksRebaseSync = behindCount > 0 && hasUncommittedChanges; const isPrimaryDisabled = disabled || syncAction !== null || isRemovingRemote || !trackingRemote || blocksRebaseSync; const isDropdownDisabled = disabled || syncAction !== null || isRemovingRemote || remotes.length === 0; - const countsLabel = t('gitView.sync.syncCounts', { ahead: aheadCount, behind: behindCount }); + const hasKnownSyncWork = aheadCount > 0 || behindCount > 0; + const primaryLabel = hasKnownSyncWork + ? t('gitView.sync.syncCounts', { ahead: aheadCount, behind: behindCount }) + : t('gitView.sync.sync'); const tooltipLabel = blocksRebaseSync ? t('gitView.sync.commitOrStashTooltip') : trackingRemote - ? t('gitView.sync.syncChangesTooltip', { ahead: aheadCount, behind: behindCount }) + ? hasKnownSyncWork + ? t('gitView.sync.syncChangesTooltip', { ahead: aheadCount, behind: behindCount }) + : t('gitView.sync.syncChanges') : t('gitView.sync.noRemoteTooltip'); const handleSync = () => { @@ -87,7 +92,7 @@ export const SyncActions: React.FC = ({ ) : ( )} - {countsLabel} + {primaryLabel} {tooltipLabel} diff --git a/packages/ui/src/lib/i18n/messages/en.ts b/packages/ui/src/lib/i18n/messages/en.ts index cfc621df..6ff7c0ec 100644 --- a/packages/ui/src/lib/i18n/messages/en.ts +++ b/packages/ui/src/lib/i18n/messages/en.ts @@ -557,6 +557,7 @@ export const dict = { 'gitView.sync.push': 'Push', 'gitView.sync.pushTooltip': 'Push changes', 'gitView.sync.pushTooltipAhead': 'Push changes ({count} ahead)', + 'gitView.sync.sync': 'sync', 'gitView.sync.syncChanges': 'Sync Changes', 'gitView.sync.syncChangesTooltip': 'Sync Changes ({behind} down, {ahead} up)', 'gitView.sync.syncChangesWithCounts': 'Sync Changes {behind}↓ {ahead}↑', @@ -705,6 +706,8 @@ export const dict = { 'gitView.toast.pulledFilesSingle': 'Pulled {count} file from {name}', 'gitView.toast.pushedToUpstream': 'Pushed to upstream', 'gitView.toast.commitOrStashBeforeSync': 'Commit or stash your changes before syncing', + 'gitView.toast.syncedPulledPluralAndPushed': 'Pulled {count} files from {name} and pushed to upstream', + 'gitView.toast.syncedPulledSingleAndPushed': 'Pulled {count} file from {name} and pushed to upstream', 'gitView.toast.syncedChanges': 'Synced changes', 'gitView.toast.rebaseAborted': 'Rebase aborted', 'gitView.toast.rebaseConflictsDetected': 'Rebase conflicts detected', diff --git a/packages/ui/src/lib/i18n/messages/es.ts b/packages/ui/src/lib/i18n/messages/es.ts index 294d3a4b..147de2cd 100644 --- a/packages/ui/src/lib/i18n/messages/es.ts +++ b/packages/ui/src/lib/i18n/messages/es.ts @@ -558,6 +558,7 @@ export const dict: Record = { "gitView.sync.push": "Push", "gitView.sync.pushTooltip": "Hacer push", "gitView.sync.pushTooltipAhead": "Hacer push ({count} por delante)", + "gitView.sync.sync": "sync", "gitView.sync.syncChanges": "Sync Changes", "gitView.sync.syncChangesTooltip": "Sync Changes ({behind} abajo, {ahead} arriba)", "gitView.sync.syncChangesWithCounts": "Sync Changes {behind}↓ {ahead}↑", @@ -706,6 +707,8 @@ export const dict: Record = { "gitView.toast.pulledFilesSingle": "Se trajo {count} archivo de {name}", "gitView.toast.pushedToUpstream": "Enviado al upstream", "gitView.toast.commitOrStashBeforeSync": "Haz commit o stash de tus cambios antes de sincronizar", + "gitView.toast.syncedPulledPluralAndPushed": "Se trajeron {count} archivos de {name} y se envió al upstream", + "gitView.toast.syncedPulledSingleAndPushed": "Se trajo {count} archivo de {name} y se envió al upstream", "gitView.toast.syncedChanges": "Cambios sincronizados", "gitView.toast.rebaseAborted": "Rebase abortado", "gitView.toast.rebaseConflictsDetected": "Se detectaron conflictos al hacer rebase", diff --git a/packages/ui/src/lib/i18n/messages/ko.ts b/packages/ui/src/lib/i18n/messages/ko.ts index 1d1bd0d3..5c3a087a 100644 --- a/packages/ui/src/lib/i18n/messages/ko.ts +++ b/packages/ui/src/lib/i18n/messages/ko.ts @@ -558,6 +558,7 @@ export const dict: Record = { 'gitView.sync.push': '푸시', 'gitView.sync.pushTooltip': '변경 사항 푸시', 'gitView.sync.pushTooltipAhead': '변경 사항 푸시({count}개 앞섬)', + 'gitView.sync.sync': 'sync', 'gitView.sync.syncChanges': 'Sync Changes', 'gitView.sync.syncChangesTooltip': 'Sync Changes({behind}개 내려받기, {ahead}개 올리기)', 'gitView.sync.syncChangesWithCounts': 'Sync Changes {behind}↓ {ahead}↑', @@ -706,6 +707,8 @@ export const dict: Record = { 'gitView.toast.pulledFilesSingle': '{name}에서 파일 {count}개를 풀했습니다', 'gitView.toast.pushedToUpstream': '업스트림에 푸시했습니다', 'gitView.toast.commitOrStashBeforeSync': '동기화하기 전에 변경 사항을 커밋하거나 stash하세요', + 'gitView.toast.syncedPulledPluralAndPushed': '{name}에서 파일 {count}개를 풀하고 업스트림에 푸시했습니다', + 'gitView.toast.syncedPulledSingleAndPushed': '{name}에서 파일 {count}개를 풀하고 업스트림에 푸시했습니다', 'gitView.toast.syncedChanges': '변경 사항을 동기화했습니다', 'gitView.toast.rebaseAborted': 'rebase 중단됨', 'gitView.toast.rebaseConflictsDetected': '리베이스 충돌이 감지되었습니다', diff --git a/packages/ui/src/lib/i18n/messages/pt-BR.ts b/packages/ui/src/lib/i18n/messages/pt-BR.ts index c7b717cc..283fcb07 100644 --- a/packages/ui/src/lib/i18n/messages/pt-BR.ts +++ b/packages/ui/src/lib/i18n/messages/pt-BR.ts @@ -558,6 +558,7 @@ export const dict: Record = { "gitView.sync.push": "Push", "gitView.sync.pushTooltip": "Fazer push", "gitView.sync.pushTooltipAhead": "Fazer push ({count} por delante)", + "gitView.sync.sync": "sync", "gitView.sync.syncChanges": "Sync Changes", "gitView.sync.syncChangesTooltip": "Sync Changes ({behind} abaixo, {ahead} acima)", "gitView.sync.syncChangesWithCounts": "Sync Changes {behind}↓ {ahead}↑", @@ -706,6 +707,8 @@ export const dict: Record = { "gitView.toast.pulledFilesSingle": "Se trajo {count} arquivo de {name}", "gitView.toast.pushedToUpstream": "Enviado ao upstream", "gitView.toast.commitOrStashBeforeSync": "Faça commit ou stash das alterações antes de sincronizar", + "gitView.toast.syncedPulledPluralAndPushed": "Foram trazidos {count} arquivos de {name} e enviados ao upstream", + "gitView.toast.syncedPulledSingleAndPushed": "Foi trazido {count} arquivo de {name} e enviado ao upstream", "gitView.toast.syncedChanges": "Alterações sincronizadas", "gitView.toast.rebaseAborted": "Rebase abortado", "gitView.toast.rebaseConflictsDetected": "Se detectaron conflitos ao hacer rebase", diff --git a/packages/ui/src/lib/i18n/messages/uk.ts b/packages/ui/src/lib/i18n/messages/uk.ts index 90456d70..3e1cc1b9 100644 --- a/packages/ui/src/lib/i18n/messages/uk.ts +++ b/packages/ui/src/lib/i18n/messages/uk.ts @@ -558,6 +558,7 @@ export const dict: Record = { "gitView.sync.push": "Push", "gitView.sync.pushTooltip": "Push змін", "gitView.sync.pushTooltipAhead": "Push змін ({count} попереду)", + "gitView.sync.sync": "sync", "gitView.sync.syncChanges": "Sync Changes", "gitView.sync.syncChangesTooltip": "Sync Changes ({behind} вниз, {ahead} вгору)", "gitView.sync.syncChangesWithCounts": "Sync Changes {behind}↓ {ahead}↑", @@ -706,6 +707,8 @@ export const dict: Record = { "gitView.toast.pulledFilesSingle": "Отримано файл: {count} з {name}", "gitView.toast.pushedToUpstream": "Надіслано в upstream", "gitView.toast.commitOrStashBeforeSync": "Закомітьте або сховайте зміни перед синхронізацією", + "gitView.toast.syncedPulledPluralAndPushed": "Отримано файлів: {count} з {name} і надіслано в upstream", + "gitView.toast.syncedPulledSingleAndPushed": "Отримано файл: {count} з {name} і надіслано в upstream", "gitView.toast.syncedChanges": "Зміни синхронізовано", "gitView.toast.rebaseAborted": "Перебазування перервано", "gitView.toast.rebaseConflictsDetected": "Виявлено конфлікти перебазування", diff --git a/packages/ui/src/lib/i18n/messages/zh-CN.ts b/packages/ui/src/lib/i18n/messages/zh-CN.ts index 4d7021cf..4dc0ac0e 100644 --- a/packages/ui/src/lib/i18n/messages/zh-CN.ts +++ b/packages/ui/src/lib/i18n/messages/zh-CN.ts @@ -558,6 +558,7 @@ export const dict: Record = { 'gitView.sync.push': '推送', 'gitView.sync.pushTooltip': '推送更改', 'gitView.sync.pushTooltipAhead': '推送更改(领先 {count})', + 'gitView.sync.sync': 'sync', 'gitView.sync.syncChanges': 'Sync Changes', 'gitView.sync.syncChangesTooltip': 'Sync Changes({behind} 下,{ahead} 上)', 'gitView.sync.syncChangesWithCounts': 'Sync Changes {behind}↓ {ahead}↑', @@ -706,6 +707,8 @@ export const dict: Record = { 'gitView.toast.pulledFilesSingle': '已从 {name} 拉取 {count} 个文件', 'gitView.toast.pushedToUpstream': '已推送到上游', 'gitView.toast.commitOrStashBeforeSync': '同步前请先提交或储藏你的更改', + 'gitView.toast.syncedPulledPluralAndPushed': '已从 {name} 拉取 {count} 个文件并推送到上游', + 'gitView.toast.syncedPulledSingleAndPushed': '已从 {name} 拉取 {count} 个文件并推送到上游', 'gitView.toast.syncedChanges': '已同步更改', 'gitView.toast.rebaseAborted': '变基已中止', 'gitView.toast.rebaseConflictsDetected': '检测到变基冲突', diff --git a/packages/vscode/src/gitService.ts b/packages/vscode/src/gitService.ts index 57db3610..ed23ad3a 100644 --- a/packages/vscode/src/gitService.ts +++ b/packages/vscode/src/gitService.ts @@ -2380,6 +2380,7 @@ export async function gitPull( } // Fallback to raw git + const beforeHead = await execGit(['rev-parse', 'HEAD'], directory); const args = ['pull']; if (options?.rebase === true) args.push('--rebase'); if (options?.remote) args.push(options.remote); @@ -2389,11 +2390,20 @@ export async function gitPull( if (result.exitCode !== 0) { throw new Error(result.stderr.trim() || result.stdout.trim() || 'Failed to pull from remote'); } - + const afterHead = await execGit(['rev-parse', 'HEAD'], directory); + const before = beforeHead.exitCode === 0 ? beforeHead.stdout.trim() : ''; + const after = afterHead.exitCode === 0 ? afterHead.stdout.trim() : ''; + const changedFiles = before && after && before !== after + ? await execGit(['diff', '--name-only', before, after], directory) + : { stdout: '', stderr: '', exitCode: 0 }; + const files = changedFiles.exitCode === 0 + ? changedFiles.stdout.split('\n').map((line) => line.trim()).filter(Boolean) + : []; + return { success: result.exitCode === 0, - summary: { changes: 0, insertions: 0, deletions: 0 }, - files: [], + summary: { changes: files.length, insertions: 0, deletions: 0 }, + files, insertions: 0, deletions: 0, };