使用go-git同步文件到gitee
go-git是golang上纯go实现的git客户端,可用来同步文件到git仓库。
为什么不用gitee官方openapi,因为我需要强制推送覆盖,官方api不支持。
下面是一个通过xml.gz文件到gitee的代码示例
package clientimport ("fmt""gin-epg/internal/app/common/util""io""os""path/filepath""strings""time""gin-epg/internal/app/store""github.com/go-git/go-git/v5""github.com/go-git/go-git/v5/config""github.com/go-git/go-git/v5/plumbing/object""github.com/go-git/go-git/v5/plumbing/transport/http"
)// SyncXmlGzToGitee 同步多个 XML.gz 文件到 Gitee,每次同步时强制覆盖历史提交记录
func SyncXmlGzToGitee() error {url := ""userName := ""password := ""// 获取配置值repoUrl, err := util.GetConfigValue("sync.repoUrl")repoUserName, err := util.GetConfigValue("sync.repoUserName")repoPassword, err := util.GetConfigValue("sync.repoPassword")if repoUrl != nil {url = repoUrl.(string)}if repoUserName != nil {userName = repoUserName.(string)}if repoPassword != nil {password = repoPassword.(string)}if url == "" || userName == "" || password == "" {return fmt.Errorf("配置错误,请检查 sync.repoUrl、sync.repoUserName 和 sync.repoPassword 是否正确")}fileNames := []interface{}{"e9.xml.gz","e7.xml.gz","e.xml.gz",}// 创建 gitee同步目录tempDirPath := filepath.Join(os.TempDir(), "gitee-sync")if err := os.MkdirAll(tempDirPath, os.ModePerm); err != nil {return fmt.Errorf("创建临时目录失败: %v", err)}fmt.Printf("临时目录路径: %s\n", tempDirPath)// 创建存储工具下载目录tempDir := filepath.Join(os.TempDir(), "xmltvsync")if err := os.MkdirAll(tempDir, os.ModePerm); err != nil {return fmt.Errorf("创建临时目录失败: %v", err)}fmt.Printf("存储工具下载目录路径: %s\n", tempDir)// 初始化 OSS 存储服务ossService := store.GlobalStoreService// 初始化或打开本地临时仓库repoPath := filepath.Join(tempDirPath, "repo")fmt.Printf("Git 仓库路径: %s\n", repoPath)// 清理旧的仓库目录(如果存在)if _, err := os.Stat(repoPath); !os.IsNotExist(err) {if err := os.RemoveAll(repoPath); err != nil {return fmt.Errorf("清理旧的仓库目录失败: %v", err)}fmt.Printf("旧的仓库目录已清理: %s\n", repoPath)}repo, err := git.PlainOpen(repoPath)if err != nil {if strings.Contains(err.Error(), "repository does not exist") {// 如果仓库不存在,则初始化一个新的仓库repo, err = git.PlainInit(repoPath, false)if err != nil {return fmt.Errorf("初始化 Git 仓库失败: %v", err)}fmt.Printf("Git 仓库初始化成功: %s\n", repoPath)} else {return fmt.Errorf("打开 Git 仓库失败: %v", err)}}// 获取工作树worktree, err := repo.Worktree()if err != nil {return fmt.Errorf("获取工作树失败: %v", err)}fmt.Printf("工作树获取成功\n")// 遍历需要同步的文件列表for _, fileInterface := range fileNames {fileName, ok := fileInterface.(string)if !ok {fmt.Printf("配置 sync.filesToSync 中包含非字符串项,跳过该项: %v\n", fileInterface)continue}localFilePath := filepath.Join(tempDir, fileName)tempFilePath := filepath.Join(repoPath, fileName)// 下载文件if err := ossService.DownloadToFile(fileName, localFilePath); err != nil {fmt.Printf("下载文件 %s 失败: %v\n", fileName, err)continue}fmt.Printf("文件下载成功: %s\n", localFilePath)// 复制文件到 Git 仓库目录if err := copyFile(localFilePath, tempFilePath); err != nil {fmt.Printf("复制文件 %s 失败: %v\n", fileName, err)continue}fmt.Printf("文件复制成功: %s\n", tempFilePath)// 添加文件到索引if _, err := worktree.Add(fileName); err != nil {fmt.Printf("添加文件 %s 到 Git 失败: %v\n", fileName, err)continue}fmt.Printf("文件 %s 添加到索引成功\n", fileName)}// 获取当前时间并格式化currentTime := time.Now().Format("2006-01-02 15:04:05")// 提交更改commitHash, err := worktree.Commit(fmt.Sprintf("同步 XML.gz 文件 - %s", currentTime), &git.CommitOptions{Author: &object.Signature{Name: "sync",Email: "sync@example.com",When: time.Now(),},})if err != nil {return fmt.Errorf("提交更改失败: %v", err)}fmt.Printf("提交成功,提交哈希: %s\n", commitHash)// 添加远程仓库(如果尚未添加)remoteName := "origin"if _, err := repo.Remote(remoteName); err != nil {if err == git.ErrRemoteNotFound {// 添加远程仓库_, err := repo.CreateRemote(&config.RemoteConfig{Name: remoteName,URLs: []string{url},})if err != nil {return fmt.Errorf("添加远程仓库失败: %v", err)}fmt.Printf("远程仓库添加成功\n")} else {return fmt.Errorf("检查远程仓库失败: %v", err)}}// 强制推送到远程仓库if err := repo.Push(&git.PushOptions{RemoteName: remoteName,RefSpecs: []config.RefSpec{config.RefSpec("refs/heads/master:refs/heads/master"),},Auth: &http.BasicAuth{Username: userName,Password: password,},Force: true,}); err != nil {return fmt.Errorf("强制推送失败: %v", err)}fmt.Printf("强制推送成功\n")return nil
}// copyFile 复制文件
func copyFile(src, dst string) error {in, err := os.Open(src)if err != nil {return err}defer in.Close()out, err := os.Create(dst)if err != nil {return err}defer out.Close()_, err = io.Copy(out, in)return err
}
这里需要强制推送,没有git历史可以减少仓库体积。不能用go-git v4版,v4版不支持强制推送。
若需要兼容win7 golang1.20 需要降低go-git版本至github.com/go-git/go-git/v5 v5.9.0
可在go.mod文件中修改版本后执行 go mod tidy