新增功能区分推送与未推送的版本
This commit is contained in:
@@ -1 +1 @@
|
|||||||
c6a7af2915380768678ecf3032701af1
|
b3473eff2f1694108cc3ae68b4ae04f0
|
||||||
|
|||||||
BIN
bin/gitpilot.exe
BIN
bin/gitpilot.exe
Binary file not shown.
@@ -19,6 +19,7 @@ import {
|
|||||||
UserOutlined,
|
UserOutlined,
|
||||||
RollbackOutlined,
|
RollbackOutlined,
|
||||||
ExclamationCircleOutlined,
|
ExclamationCircleOutlined,
|
||||||
|
CloseCircleOutlined,
|
||||||
} from '@ant-design/icons-vue'
|
} from '@ant-design/icons-vue'
|
||||||
import { Modal } from 'ant-design-vue'
|
import { Modal } from 'ant-design-vue'
|
||||||
import { AppService } from '../../bindings/github.com/zhuy1228/GitPilot/internal/app'
|
import { AppService } from '../../bindings/github.com/zhuy1228/GitPilot/internal/app'
|
||||||
@@ -614,6 +615,33 @@ async function resetToCommit(commit, mode = 'hard') {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function revertCommit(commit) {
|
||||||
|
if (!props.project?.path || !commit) return
|
||||||
|
Modal.confirm({
|
||||||
|
title: '确认撤回提交',
|
||||||
|
icon: h(ExclamationCircleOutlined),
|
||||||
|
content: h('div', [
|
||||||
|
h('p', '将创建一个新提交来撤回以下提交的更改:'),
|
||||||
|
h('p', { style: 'font-family: monospace; color: #89b4fa;' }, `${commit.shortHash} - ${commit.message}`),
|
||||||
|
h('p', { style: 'color: var(--text-muted); font-size: 12px; margin-top: 8px;' }, '此操作会生成一个新的反向提交,不会丢失历史记录。'),
|
||||||
|
]),
|
||||||
|
okText: '确认撤回',
|
||||||
|
cancelText: '取消',
|
||||||
|
okButtonProps: { danger: true },
|
||||||
|
async onOk() {
|
||||||
|
try {
|
||||||
|
await AppService.RevertCommit(props.project.path, commit.hash)
|
||||||
|
await loadStatus()
|
||||||
|
selectedCommit.value = null
|
||||||
|
commitDiff.value = ''
|
||||||
|
} catch (e) {
|
||||||
|
console.error('撤回提交失败:', e)
|
||||||
|
Modal.error({ title: '撤回失败', content: String(e) })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function formatTime(ts) {
|
function formatTime(ts) {
|
||||||
if (!ts) return ''
|
if (!ts) return ''
|
||||||
const d = new Date(ts * 1000)
|
const d = new Date(ts * 1000)
|
||||||
@@ -842,16 +870,29 @@ function formatTime(ts) {
|
|||||||
v-for="log in commitLogs"
|
v-for="log in commitLogs"
|
||||||
:key="log.hash"
|
:key="log.hash"
|
||||||
class="commit-item"
|
class="commit-item"
|
||||||
:class="{ active: selectedCommit?.hash === log.hash }"
|
:class="{ active: selectedCommit?.hash === log.hash, unpushed: !log.pushed }"
|
||||||
@click="selectCommit(log)"
|
@click="selectCommit(log)"
|
||||||
>
|
>
|
||||||
<div class="commit-msg-row">
|
<div class="commit-msg-row">
|
||||||
|
<span v-if="!log.pushed" class="commit-unpushed-dot" title="未推送"></span>
|
||||||
<div class="commit-msg">{{ log.message }}</div>
|
<div class="commit-msg">{{ log.message }}</div>
|
||||||
<a-dropdown :trigger="['click']" @click.stop>
|
<div class="commit-action-btns" @click.stop>
|
||||||
|
<!-- 撤回按钮 -->
|
||||||
<a-button
|
<a-button
|
||||||
type="text"
|
type="text"
|
||||||
size="small"
|
size="small"
|
||||||
class="commit-reset-btn"
|
class="commit-action-btn"
|
||||||
|
title="撤回此提交"
|
||||||
|
@click.stop="revertCommit(log)"
|
||||||
|
>
|
||||||
|
<template #icon><CloseCircleOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
<!-- 回滚下拉 -->
|
||||||
|
<a-dropdown :trigger="['click']">
|
||||||
|
<a-button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
class="commit-action-btn"
|
||||||
:loading="resetLoading"
|
:loading="resetLoading"
|
||||||
@click.stop
|
@click.stop
|
||||||
>
|
>
|
||||||
@@ -875,8 +916,10 @@ function formatTime(ts) {
|
|||||||
</template>
|
</template>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="commit-meta">
|
<div class="commit-meta">
|
||||||
<span class="commit-hash">{{ log.shortHash }}</span>
|
<span class="commit-hash">{{ log.shortHash }}</span>
|
||||||
|
<span v-if="!log.pushed" class="commit-push-tag">未推送</span>
|
||||||
<span class="commit-author"><UserOutlined /> {{ log.author }}</span>
|
<span class="commit-author"><UserOutlined /> {{ log.author }}</span>
|
||||||
<span class="commit-time">{{ formatTime(log.timestamp) }}</span>
|
<span class="commit-time">{{ formatTime(log.timestamp) }}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -1379,22 +1422,52 @@ function formatTime(ts) {
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.commit-reset-btn {
|
.commit-action-btns {
|
||||||
visibility: hidden;
|
display: flex;
|
||||||
color: var(--text-muted) !important;
|
align-items: center;
|
||||||
|
gap: 0;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commit-action-btn {
|
||||||
|
color: var(--text-muted) !important;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.commit-reset-btn:hover {
|
.commit-action-btn:hover {
|
||||||
color: #f38ba8 !important;
|
color: #f38ba8 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.commit-item:hover .commit-reset-btn {
|
.commit-item:hover .commit-action-btns {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 未推送标识 */
|
||||||
|
.commit-unpushed-dot {
|
||||||
|
width: 7px;
|
||||||
|
height: 7px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #a6e3a1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commit-push-tag {
|
||||||
|
font-size: 10px;
|
||||||
|
padding: 0 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: rgba(166, 227, 161, 0.15);
|
||||||
|
color: #a6e3a1;
|
||||||
|
line-height: 16px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commit-item.unpushed {
|
||||||
|
border-left: 2px solid #a6e3a1;
|
||||||
|
}
|
||||||
|
|
||||||
.commit-msg {
|
.commit-msg {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
|
|||||||
@@ -282,6 +282,16 @@ export function ResetProject(path, hash, mode) {
|
|||||||
return $Call.ByID(2061148684, path, hash, mode);
|
return $Call.ByID(2061148684, path, hash, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RevertCommit 撤回指定提交(生成一个反向提交)
|
||||||
|
* @param {string} path
|
||||||
|
* @param {string} hash
|
||||||
|
* @returns {$CancellablePromise<void>}
|
||||||
|
*/
|
||||||
|
export function RevertCommit(path, hash) {
|
||||||
|
return $Call.ByID(1334788539, path, hash);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SelectDirectory 打开系统文件夹选择器,返回选中的路径
|
* SelectDirectory 打开系统文件夹选择器,返回选中的路径
|
||||||
* @returns {$CancellablePromise<string>}
|
* @returns {$CancellablePromise<string>}
|
||||||
|
|||||||
@@ -133,6 +133,13 @@ export class CommitLog {
|
|||||||
*/
|
*/
|
||||||
this["message"] = "";
|
this["message"] = "";
|
||||||
}
|
}
|
||||||
|
if (!("pushed" in $$source)) {
|
||||||
|
/**
|
||||||
|
* @member
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this["pushed"] = false;
|
||||||
|
}
|
||||||
|
|
||||||
Object.assign(this, $$source);
|
Object.assign(this, $$source);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -569,6 +569,7 @@ type CommitLog struct {
|
|||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Timestamp int64 `json:"timestamp"`
|
Timestamp int64 `json:"timestamp"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
|
Pushed bool `json:"pushed"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BranchInfo 分支信息
|
// BranchInfo 分支信息
|
||||||
@@ -589,7 +590,39 @@ func (s *AppService) GetCommitLog(path string, count int) ([]CommitLog, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("获取提交历史失败: %w", err)
|
return nil, fmt.Errorf("获取提交历史失败: %w", err)
|
||||||
}
|
}
|
||||||
return parseCommitLog(out), nil
|
logs := parseCommitLog(out)
|
||||||
|
|
||||||
|
// 获取当前分支名,查询未推送的提交
|
||||||
|
branch, brErr := s.gitClient.Branch(path)
|
||||||
|
if brErr == nil {
|
||||||
|
branch = strings.TrimSpace(branch)
|
||||||
|
unpushedOut, upErr := s.gitClient.UnpushedCommits(path, branch)
|
||||||
|
unpushedSet := make(map[string]bool)
|
||||||
|
if upErr == nil {
|
||||||
|
for _, h := range strings.Split(strings.TrimSpace(unpushedOut), "\n") {
|
||||||
|
if h != "" {
|
||||||
|
unpushedSet[h] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := range logs {
|
||||||
|
logs[i].Pushed = !unpushedSet[logs[i].Hash]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return logs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevertCommit 撤回指定提交(生成一个反向提交)
|
||||||
|
func (s *AppService) RevertCommit(path, hash string) error {
|
||||||
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("项目路径不存在: %s", path)
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(hash) == "" {
|
||||||
|
return fmt.Errorf("提交哈希不能为空")
|
||||||
|
}
|
||||||
|
_, err := s.gitClient.RevertCommit(path, strings.TrimSpace(hash))
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseCommitLog(output string) []CommitLog {
|
func parseCommitLog(output string) []CommitLog {
|
||||||
|
|||||||
@@ -119,6 +119,16 @@ func (g *GitClient) Log(path string, count int) (string, error) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnpushedCommits 获取当前分支上未推送到远程的提交哈希列表
|
||||||
|
func (g *GitClient) UnpushedCommits(path, branch string) (string, error) {
|
||||||
|
return g.Run(path, "rev-list", "origin/"+branch+"..HEAD")
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevertCommit 撤回指定提交(创建一个反向提交)
|
||||||
|
func (g *GitClient) RevertCommit(path, hash string) (string, error) {
|
||||||
|
return g.Run(path, "revert", "--no-edit", hash)
|
||||||
|
}
|
||||||
|
|
||||||
// BranchList 获取所有本地分支
|
// BranchList 获取所有本地分支
|
||||||
func (g *GitClient) BranchList(path string) (string, error) {
|
func (g *GitClient) BranchList(path string) (string, error) {
|
||||||
return g.Run(path, "branch", "--format=%(refname:short)\t%(HEAD)")
|
return g.Run(path, "branch", "--format=%(refname:short)\t%(HEAD)")
|
||||||
|
|||||||
Reference in New Issue
Block a user