草庐IT

Git2go : How to handle simple merge conflicts

coder 2023-06-28 原文

对于一个简单的实时编码环境,我正在编写一个 git add、commit 和 push 函数,它工作正常,除了冲突的情况,当两个用户在文件的同一部分编码时。它正确执行冲突分析并加载结果:

// Live-Editor, Processing / Javascript
fill(130, 52, 130);
<<<<<<< HEAD
textSize(130);
=======
textSize(120);
>>>>>>> master
text( "?",160, 100);

显示 git 风格的差异。但是当我随后在编辑器中进行更改并再次添加/提交/推送时,它会导致相同的冲突。就像它不“记得”冲突已经存在并且再次出现一样。 (与 git 命令行行为不同。)

这是我的代码(我删除了错误处理以使其更短......)

// Add
repo, err := git.OpenRepository(dir)
index, err := repo.Index()
err = index.AddAll([]string{}, git.IndexAddDefault, nil)
err = index.Write()  
treeId, err := index.WriteTreeTo(repo)
tree, err := repo.LookupTree(treeId)

// Commit
sig := &git.Signature{
    Name:  userName,
    Email: userName + "@" + beego.AppConfig.String("userdata::emailserver"),
    When:  time.Now(),
}
var currentCommit *git.Oid
if firstCommit == true {
    _, err = repo.CreateCommit("HEAD", sig, sig, message, tree)
} else {
    currentBranch, err := repo.Head()
    currentTip, err := repo.LookupCommit(currentBranch.Target())
    currentCommit, err = repo.CreateCommit("HEAD", sig, sig, message, tree, currentTip)
}

remote, err := repo.LookupRemote("origin")

// Pull
if firstCommit == false {
    // Pull possible changes from remote repo
    err = remote.Fetch([]string{}, nil, "")
    remoteBranch, err := repo.LookupReference("refs/remotes/origin/master")
    annotatedCommit, err := repo.AnnotatedCommitFromRef(remoteBranch)

    // Do the merge analysis
    mergeHeads := make([]*git.AnnotatedCommit, 1)
    mergeHeads[0] = annotatedCommit
    analysis, _, err := repo.MergeAnalysis(mergeHeads)

    if analysis&git.MergeAnalysisUpToDate == 0 && analysis&git.MergeAnalysisNormal != 0 {

        err := repo.Merge([]*git.AnnotatedCommit{annotatedCommit}, nil, nil)

        // Check for conflicts
        index, err := repo.Index()    
        if index.HasConflicts() {
            err = index.Write()
            return errors.New("Conflicts")
        }

        // No unsolvable conflicts, commit it
        treeId, err := index.WriteTree()
        tree, err := repo.LookupTree(treeId)
        localCommit, err := repo.LookupCommit(currentCommit)
        remoteCommit, err := repo.LookupCommit(remoteBranch.Target())
        repo.CreateCommit("HEAD", sig, sig, "Merge commit", tree, localCommit, remoteCommit)
        repo.StateCleanup()
    }
}

// Push
err = remote.Push([]string{"refs/heads/master"}, nil, sig, message)

我猜关键部分在 //Check for conflicts 之后 不知何故,这使 git 目录处于一种状态,让它执行相同的分析。我考虑过在用户做出更改并再次提交项目后不进行分析,但有可能在此期间另一个用户已经在远程仓库中更改了某些内容。

如何处理与 git2go 的此类冲突的好方法?

最佳答案

我解决了这个问题。碰撞检测工作正常。如果发生无法自动解决的冲突,则将控制权交还给用户。他进行了更改,但在冲突分析再次发生之前,这些更改并未提交。

这里是完整的代码(“merge 提交(如果 - 现在希望解决 - 冲突)是至关重要的。”之后的部分):

//////////////////////////////////////////////////////////
// GitAddCommitPush
func GitAddCommitPush(userName string, dir string, message string, firstCommit bool) error {

    ///////////////////////////////////////////////////////////////////////
    // Add
    //
    // 1 Open repository
    repo, err := git.OpenRepository(dir)
    if err != nil {
        beego.Error("OpenRepository - ", err)
    }

    // 2 Retrieve index
    index, err := repo.Index()
    if err != nil {
        beego.Error("Index - ", err)
    }

    // 3 Remember if we had conflicts before we added everything to the index
    indexHadConflicts := index.HasConflicts()

    // 4 Add everything to the index
    err = index.AddAll([]string{}, git.IndexAddDefault, nil)
    if err != nil {
        beego.Error("AddAll - ", err)
    }

    // 5 Write the index (so git knows about it)
    err = index.Write()
    if err != nil {
        beego.Error("Write - ", err)
    }

    // 6 Write the current index tree to the repo
    treeId, err := index.WriteTreeTo(repo)
    if err != nil {
        beego.Error("WriteTreeTo - ", err)
    }

    /////////////////////////////////////////////////////////////////////////////////////////////
    // Commit
    //
    // 1 Retrieve the tree we just wrote (git's reference of it that it made in the last step)
    tree, err := repo.LookupTree(treeId)
    if err != nil {
        beego.Error("LookupTree - ", err)
    }

    // 2 Create a signature
    sig := &git.Signature{
        Name:  userName,
        Email: userName + "@" + beego.AppConfig.String("userdata::emailserver"),
        When:  time.Now(),
    }

    // 3 Get remote now (as we need it for both, fetch and later push )
    remote, err := repo.LookupRemote("origin")
    if err != nil {
        remote, err = repo.CreateRemote("origin", repo.Path())
        if err != nil {
            beego.Error("CreateRemote - ", err)
        }
    }

    // 4 Read the remote branch
    remoteBranch, err := repo.LookupReference("refs/remotes/origin/master")
    if err != nil {
        beego.Error("Fetch 2 - ", err)
    }

    // 5 Determine if this is a first commit ...
    if firstCommit == true {

        // 5a ... then create a new one
        _, err = repo.CreateCommit("HEAD", sig, sig, message, tree)

    } else {

        // 5b ... or retrieve current head
        currentBranch, err := repo.Head()
        if err != nil {
            beego.Error("Head - ", err)
        }

        // 6 Retrieve current commit
        currentTip, err := repo.LookupCommit(currentBranch.Target())
        if err != nil {
            beego.Error("LookupCommit - ", err)
        }

        // 7 Create a new one on top
        currentCommit, err := repo.CreateCommit("HEAD", sig, sig, message, tree, currentTip)
        if err != nil {
            beego.Error("CreateCommit - ", err)
        }

        ////////////////////////////////////////////////////////////////////////////////////
        // Merge commit (in case of -- now hopefully resolved -- conflicts)
        //
        // 1 If there were conflicts, do the merge commit
        if indexHadConflicts == true {

            // 2 Retrieve the local commit
            localCommit, err := repo.LookupCommit(currentCommit)
            if err != nil {
                beego.Error("Fetch 11 - ", err)
            }

            // 3 Retrieve the remote commit
            remoteCommit, err := repo.LookupCommit(remoteBranch.Target())
            if err != nil {
                beego.Error("Fetch 12 - ", err)
            }

            // 4 Create a new one
            repo.CreateCommit("HEAD", sig, sig, "Merge commit", tree, localCommit, remoteCommit)

            // 5 Clean up
            repo.StateCleanup()
        }

        ///////////////////////////////////////////////////////////////////////////////////
        // Pull (Fetch and Commit)
        //
        // 1 Fetch it (pull without commit)
        err = remote.Fetch([]string{}, nil, "")
        if err != nil {
            beego.Error("Fetch 1 - ", err)
        }

        // 2 Perform an annotated commit
        annotatedCommit, err := repo.AnnotatedCommitFromRef(remoteBranch)
        if err != nil {
            beego.Error("Fetch 3 - ", err)
        }

        // 3 Do the merge analysis
        mergeHeads := make([]*git.AnnotatedCommit, 1)
        mergeHeads[0] = annotatedCommit
        analysis, _, err := repo.MergeAnalysis(mergeHeads)
        if err != nil {
            beego.Error("Fetch 4 - ", err)
        }

        // 4 Check if something happend
        if analysis&git.MergeAnalysisUpToDate == 0 && analysis&git.MergeAnalysisNormal != 0 {

            // 5 Yes! First just merge changes
            if err := repo.Merge([]*git.AnnotatedCommit{annotatedCommit}, nil, nil); err != nil {
                beego.Error("Fetch 5 - ", err)
            }

            // 6 Retrieve the index after that treatment
            index, err := repo.Index()
            if err != nil {
                beego.Error("Fetch 6 - ", err)
            }

            // 7 Check for conflicts
            if index.HasConflicts() {

                // 7a There are not automaticly solvable conflicts ... give them back to the user
                beego.Trace("Conflicts! Write new index and return.", index)
                err = index.Write()
                if err != nil {
                    beego.Error("Write - ", err)
                }

                return errors.New("Conflicts")
            }

            // 8 Write the new tree
            treeId, err := index.WriteTree()
            if err != nil {
                beego.Error("Fetch 9 - ", err)
            }

            // 9 Retrieve the new tree
            tree, err := repo.LookupTree(treeId)
            if err != nil {
                beego.Error("Fetch 10 - ", err)
            }

            // 10 Retrieve the local commit
            localCommit, err := repo.LookupCommit(currentCommit)
            if err != nil {
                beego.Error("Fetch 11 - ", err)
            }

            // 11 Retrieve the remote commit
            remoteCommit, err := repo.LookupCommit(remoteBranch.Target())
            if err != nil {
                beego.Error("Fetch 12 - ", err)
            }

            // 12 Create a new one
            repo.CreateCommit("HEAD", sig, sig, "Merge commit", tree, localCommit, remoteCommit)

            // 13 Clean up
            repo.StateCleanup()
        }
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////
    // Push
    err = remote.Push([]string{"refs/heads/master"}, nil, sig, message)
    if err != nil {
        beego.Error("Push - ", err)
    }

    return err
}

关于Git2go : How to handle simple merge conflicts,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37072576/

有关Git2go : How to handle simple merge conflicts的更多相关文章

  1. git使用常见问题(提交代码,合并冲突) - 2

    文章目录git常用命令(简介,详细参数往下看)Git提交代码步骤gitpullgitstatusgitaddgitcommitgitpushgit代码冲突合并问题方法一:放弃本地代码方法二:合并代码常用命令以及详细参数gitadd将文件添加到仓库:gitdiff比较文件异同gitlog查看历史记录gitreset代码回滚版本库相关操作远程仓库相关操作分支相关操作创建分支查看分支:gitbranch合并分支:gitmerge删除分支:gitbranch-ddev查看分支合并图:gitlog–graph–pretty=oneline–abbrev-commit撤消某次提交git用户名密码相关配置g

  2. ruby - Dropbox 类似 git 的服务——没有 rsync 和 inotify - 2

    关于如何使用git设置类似Dropbox的服务,您有什么建议吗?您认为git是解决此问题的合适工具吗?我在考虑使用git+rush解决方案,你觉得怎么样? 最佳答案 检查这个开源项目:https://github.com/hbons/SparkleShare来自项目的自述文件:Howdoesitwork?SparkleSharecreatesaspecialfolderonyourcomputer.Youcanaddremotelyhostedfolders(or"projects")tothisfolder.Theseprojec

  3. ruby - 混帐 & ruby : How can I unset the GIT_DIR variable from inside a ruby script? - 2

    我编写了一个非常简单的“部署”脚本,作为我的裸git存储库中的post-updateHook运行。变量如下livedomain=~/mydomain.comstagingdomain=~/stage.mydomain.comgitrepolocation=~/git.mydomain.com/thisrepo.git(bare)core=~/git.mydomain.com/thisrepo.gitcore==addedremoteintoeachlive&stagegitslive和stage都初始化了gitrepos(非裸),我已经将我的裸仓库作为远程添加到它们中的每一个(名为co

  4. ruby - 让 bundler 使用 http : instead of git:? - 2

    我正在安装gitlabhq,并且在Gemfile中有对某些资源的“git://...”的引用。但是,我在公司防火墙后面,所以我必须使用http://。我可以手动编辑Gemfile,但我想知道是否有另一种方法告诉bundler使用http://作为git存储库? 最佳答案 您可以通过运行gitconfig--globalurl."https://".insteadOfgit://或通过将以下内容添加到~/.gitconfig:[url"https://"]insteadOf=git://

  5. ruby-on-rails - 安装 active admin 时 activeadmin.git (at master) is not yet checked out 错误 - 2

    Activeadmingem已添加到我的rails项目中,但每次我尝试安装railsgactive_admin:install时,我都会收到类似的错误git://github.com/activeadmin/activeadmin.git(atmaster)isnotyetcheckedout.Runbundleinstallfirst.我肯定在运行“railsgactive_admin:install”之前运行了bundle。运行“bundleshow”后,我看到我已将“*activeadmin(1.0.0.pre3f916d6)”添加到我的项目中,但不断收到此错误消息。我的gem文

  6. ruby-on-rails - Textmate 'Go to symbol' 相当于 Vim - 2

    在Railcasts上,我注意到一个非常有趣的功能“转到符号”窗口。它像Command-T一样工作,但显示当前文件中可用的类和方法。如何在vim中获取它? 最佳答案 尝试:helptags有各种程序和脚本可以生成标记文件。此外,标记文件格式非常简单,因此很容易将sed(1)或类似的脚本组合在一起,无论您使用何种语言,它们都可以生成标记文件。轻松获取标记文件(除了下载生成器之外)的关键在于格式化样式而不是实际解析语法。 关于ruby-on-rails-Textmate'Gotosymbol

  7. ruby - git:从 bitbucket 导出并导入 github(带提交) - 2

    我在bitbucket上创建了一个私有(private)git存储库并提交了代码。现在我想导出所有(提交、代码、历史记录)并将其导入github上的gitrepo。有没有办法做到这一点?谢谢 最佳答案 在本地检查所有内容到您的计算机和gitpull。创建一个github存储库将此存储库添加为您的第二个远程(“使用gitremote添加githubURL”)推送到第二个Remote 关于ruby-git:从bitbucket导出并导入github(带提交),我们在StackOverflow

  8. Unity 报错No ‘git‘ executable was found. Please install Git on your system then restart - 2

    亲测可用。Anerroroccurredwhileresolvingpackages:Projecthasinvaliddependencies: com.unity.xxx:No'git'executablewasfound.PleaseinstallGitonyour  systemthenrestartUnityandUnityHub在我们使用PackageManager时,Unity允许我们使用Git上的package(点击加号,选择addpackagefromgitURL,或者是直接在Asset/Packages/manifest.json中添加包名)。但是这种操作需要我们事先装好g

  9. ruby - RSpec Git Bash Windows——缺少颜色? - 2

    我在Windows上使用GitBash来完成我的大部分Rails工作,每次我运行bundleexecrspecspec它都会提醒我“你必须geminstallwin32console才能使用Windows上的颜色”,然后以纯黑色和白色运行RSpec。但是我确实安装了win32console,当我在列表中运行gemlist时,它有win32console(1.3.0x86-mingw32)。RSpec工作正常,但我希望它有一些颜色。我用谷歌搜索了这个并找到了多种解决方案,但似乎没有一个适合我。有人可以写出在GitBashforWindows上使用RSpec获取颜色的“循序渐进”方法吗?

  10. ruby - git 最好的 ruby​​ api 是什么? - 2

    我想实现一个Rake任务,自动执行一些我必须完成的任务,以便将我的更改从开发转移到生产(是的,我知道有像Capistrano这样的东西,它对我来说太多了).中间是gitadd-i等一些交互命令,以及一系列commit和push。在生产方面,将有pull和Assets任务要做。一直输入相同的命令很乏味,所以我想完全自动化。我还没有找到Git的RubyAPI。它应该在Windows7下工作,并且至少允许以下命令:gitadd、gitstatus、gitcommit、gitpush,gitpull. 最佳答案 我知道,坏习惯,但我想记录一

随机推荐