2016-05-06 75 views
2

對於簡單的實時編碼環境,我正在編寫一個git添加,提交和推送功能,當兩個用戶在同一部分中編碼時,的文件。它正確執行衝突分析並加載結果:Git2go:如何處理簡單的合併衝突

// 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的這種衝突的好方法?

+0

此代碼不會告訴你做什麼當發生衝突時,這似乎就是你所問的。分析不會因爲你在合併而改變,因爲HEAD和遠程分支不會改變,但是這並沒有告訴你任何關於你現在正在進行的合併。 –

+0

是的,看起來我在第一個循環中做了所有事情,直到我檢測到衝突並返回編輯器,告訴用戶進行更改並再次保存項目。然後當用戶保存該項目時,我只需調用相同的函數並獲得相同的結果。我只是不知道如何檢測這個函數,索引處於不同的狀態,有不同的路徑沒有彙集在一起​​。你有一個提示,我怎麼能找到這個? – Michael

+0

分析與當前操作無關。檢查當前的操作,看看你是否在合併,並且要求索引查看是否有衝突,這樣可以避免提交;如果沒有衝突,那麼你可以把它寫成一棵樹,並使用那棵樹創建一個提交,就像任何其他時間一樣 –

回答

1

我解決了這個問題。碰撞檢測工作正常。如果發生不能自動解決的衝突,控制權將交還給用戶。他做出了改變,在衝突分析再次發生之前,這些改變沒有發生。

下面是完整的代碼(後一節「合併提交(在以下情況下 - 現在希望解決 - 衝突)是至關重要的。」):

////////////////////////////////////////////////////////// 
// 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 
}