1. 程式人生 > >Git學習6 Git衝突模擬與解決

Git學習6 Git衝突模擬與解決

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

                       

在真實的Git執行環境中,往往涉及多個使用者對版本倉庫的協作,而每個使用者都有一個完整的Git版本倉庫副本,所以在把各自的操作結果推送到遠端倉庫的時候出現衝突的可能性就非常高。

在Git中解決衝突的一個優雅方式是:首先通過命令git fetch獲取遠端倉庫最新的修改,然後執行命令git merge將本地的操作結果(實際上就是一個commit)與遠端倉庫的修改(遠端倉庫最新的commit)進行合併,如果在合併的過程沒有發生衝突,那麼Git會生成一個新的commit,並自動提交。但是,合併並非總是成功的,因為合併的不同提交可能是同時修改了同一個檔案相同區域的內容,這樣就會導致衝突。衝突發生後合併操作會終止,在本地解決衝突後,除非放棄此次合併,需要更新暫存區,再提交,最終完成合並過程。

合併示意圖

 

git fetchgit merge

操作可以使用一個命令git pull獨立完成

下面的簡圖描繪了git pull操作的過程。

在初始狀態,本地倉庫和遠端倉庫可能是這樣的:

git-conflict-1

從遠端倉庫執行git fetch命令後:

git-conflict-2

執行git merge操作後是這樣的:

git-conflict-3

最後推送到遠端倉庫是這樣的:

git-conflict-4


模擬衝突操作

為了模擬多使用者操作一個共享倉庫併產生衝突的情況,需要有一個共享倉庫,為了簡便,可以直接在本地使用git init命令初始化一個共享倉庫。

首先執行如果命令初始化一個共享倉庫:

git init --bare /home/rhwayfun/java/notes/repos/share
.git
  • 1

這樣就在響應目錄下生成了一個裸倉庫(沒有工作區的倉庫稱為裸倉庫)。然後在目錄/home/rhwayfun/java/notes/to下面建立兩個資料夾user1user2,模擬兩個使用者。並在各自的目錄下克隆上面建立的share倉庫,以上操作命令如下:

mkdir user1cd /home/rhwayfun/java/notes/to/user1git clone file:///home/rhwayfun/java/notes/repos/share.git projectcd ..mkdir user2cd user2/git clone file:///home/rhwayfun/java/notes/repos/share.git project
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

以上命令執行完畢後就分別在user1和user2兩個使用者目錄下有了最新的遠端倉庫。

在user1目錄執行如下操作:

cd user1/projectgit config user.name user1git config user.email user1@163.commkdir teamecho "I'm user1." > team/user1.txtgit add user1.txtgit commit -m "create team/user1.txt"git push
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在user2目錄執行如下操作:

cd user2/projectgit config user.name user2git config user.email user2@163.commkdir teamecho "I'm user2." > team/user2.txtgit add user2.txtgit commit -m "create team/user2.txt"git push
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在user2執行git push操作的時候出現了異常資訊:

 

To file:///home/rhwayfun/java/notes/repos2/share.git
   ! [rejected]        master -> master (fetch first)

可知,user2的push操作被拒絕,而被拒絕的原因在於本地的版本庫不是最新的,需要首先獲取最新的遠端庫的提交才能繼續後面的執行。因為如果沒有基於最新的版本庫倉庫操作可以降低衝突發生的可能性。在更新本地倉庫之前,可以先分析一下,user1在team目錄增加了user1.txt,而user2在team目錄增加了user2.txt,所以從邏輯上兩者的操作是沒有衝突的。再根據對合並的說明,user2執行git pull應該會自動合併。

執行git pull命令後,繼續執行如下的命令,檢視提交日誌:

git log --oneline --decorate --graph --all
   
  • 1

日誌如下:

 

*   0432ca1 (HEAD -> master) Merge branch ‘master’ of file:///home/rhwayfun/java/notes/repos2/share
  |\
  | * 5f642a9 (origin/master) create team/user2.txt
  * 14cc834 create team/user1.txt

可以看到user1和user2的提交合併到一個新的提交0432ca1。所以與之前的分析是吻合的。

但是,可以發現origin/master(這是遠端倉庫的引用)的提交滯後與user2的提交,因此只需要執行git push就可以將user2的提交更新到共享倉庫。

執行後日志輸出如下:

 

*   0432ca1 (HEAD -> master, origin/master) Merge branch ‘master’ of file:///home/rhwayfun/java/notes/repos2/share
  |\
  | * 5f642a9 create team/user2.txt
  * 14cc834 create team/user1.txt

由於user2又進行了一次更新,所以需要切換到user1目錄執行如下操作:

cd user1/project//獲取最新的提交git pull
   
  • 1
  • 2
  • 3

衝突解決

現在user1和user2的本地倉庫都是最新的了,為了製造衝突,可以在user1目錄執行如下操作:

cd user1/projecttouch README.txtecho "Hello, user1." > README.txtgit add README.txtgit commit -m "create README.txt"git push
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

切換到user2目錄,然後執行如下操作:

cd user2/projecttouch README.txtecho "Hello, user2." > README.txtgit add README.txtgit commit -m "create README.txt"git push
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

發現在執行git push的時候失敗,於是執行git pull獲取最新的提交,但是好像仍然失敗了,日誌如下:

 

U README.txt
  Pull is not possible because you have unmerged files.
  Please, fix them up in the work tree, and then use ‘git add/rm ’
  as appropriate to mark resolution and make a commit.

git 提示我們README.txt在拉取最新的提交的時候發生了衝突,需要在工作區先解決衝突,然後重新將衝突檔案新增到暫存區,再執行提交。

為了檢視發生衝突的檔案,可以執行如下名命令:

// 檢視暫存區中記錄的衝突檔案git ls-files -s
   
  • 1
  • 2

日誌如下:

 

100644 ea9df2ef42c073de18bde4ebdf50e0ac6b1cdd2d  2     README.txt
  100644 633d2ed9d0ae01d0d07136c5b5bd857e4d945c14  3   README.txt
  100644 17874eaa4a398cc94ed294c93fdbf50f7f843d88  0  team/user1.txt
  100644 2dcb7b6ac06d93ea8e6af21ded690f5e171a407c  0  team/user2.txt

編號為2表示暫存區用於儲存衝突檔案在當前分支中修改的副本,檢視該檔案的內容執行如下命令:

git show :2:README.txt
   
  • 1

輸出結果為

 

Hello, user2.

編號為3的為暫存區用於儲存當前衝突檔案在合併版本中修改的副本

git show :3:README.txt
   
  • 1

輸出結果為:

 

Hello, user1.

最後看看工作區的README.txt檔案的內容:

cat README.txt
   
  • 1

輸出結果:

<<<<<<< HEADHello, user2.=======Hello, user1.>>>>>>> 04eed972e27e23a9874f984f08d6567e565d3436
   
  • 1
  • 2
  • 3
  • 4
  • 5

其中特殊標識<<<<<<<和=======之間的內容是當前分支所更新的內容,特殊標識=======和>>>>>>>之間的內容是所合併的版本更改的內容。所以只需要手動解決這個衝突就可以,將README.txt檔案修改如下:

Hello, user2 and user1.
   
  • 1

在user2目錄下執行如下操作就可以解決衝突了。

//加上-u引數表示把工作區被跟蹤的檔案新增到暫存區git add -ugit commit -m "Merge README.txt: Hello, user2 and user1."git push
   
  • 1
  • 2
  • 3
  • 4

重新執行命令:

git ls-files -s
   
  • 1

輸出:

 

100644 2ba0d56dda48b03ef57e5fbcd793f7de1103aa0e 0 README.txt
  100644 17874eaa4a398cc94ed294c93fdbf50f7f843d88 0   team/user1.txt
  100644 2dcb7b6ac06d93ea8e6af21ded690f5e171a407c 0   team/user2.txt

可以看到所有的編號都變成了0,這樣就說明已經成功解決了衝突。

小結

通過以上實際操作認識了衝產生了原因和具體解決衝突的方法,以及在解決衝突過程中使用到一些有用的命令。需要提的一點是,在工作區修改衝突檔案時可以使用圖形工作完成,不過樓主覺得Linux下的vim編輯器就挺好用的,所有沒有介紹使用圖形工作修改衝突檔案的內容,但本質都是對衝突檔案進行編譯從而解決衝突的過程。

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述