2014-06-16 26 views
2

我參與了以下git會議。如你所見,當我回到master分支的頭部時,git報告文件y.y已被刪除。這已被ls確認。但是當我檢出早先的提交併返回到master時,該文件再次出現。文件消失/重新出現在git中

我總共有初學者git,但我不能理解爲什麼git checkout master只有通過只讀命令分隔才能給出兩個不同的結果。

[email protected]:~/ht$ git log --oneline 
f065234 add y.y 
04a7340 2nd commit 
b6ca522 init commit 
[email protected]:~/ht$ git checkout master 
D y.y 
Switched to branch 'master' 
[email protected]:~/ht$ ls 
x.x x.y 
[email protected]:~/ht$ git checkout HEAD~1 
Note: checking out 'HEAD~1'. 

You are in 'detached HEAD' state. You can look around, make experimental 
changes and commit them, and you can discard any commits you make in this 
state without impacting any branches by performing another checkout. 

If you want to create a new branch to retain commits you create, you may 
do so (now or later) by using -b with the checkout command again. Example: 

    git checkout -b new_branch_name 

HEAD is now at 04a7340... 2nd commit 
[email protected]:~/ht$ ls 
x.x x.y 
[email protected]:~/ht$ git checkout HEAD~1 
Previous HEAD position was 04a7340... 2nd commit 
HEAD is now at b6ca522... init commit 
[email protected]:~/ht$ ls 
x.x 
[email protected]:~/ht$ git checkout master 
Previous HEAD position was b6ca522... init commit 
Switched to branch 'master' 
[email protected]:~/ht$ ls 
x.x x.y y.y 
+0

你的git版本是什麼? –

回答

1

這將是因爲:

  • 當你簽出HEAD~1y.y在那裏。
  • 但是當你再次被檢出master HEADy.y現在視爲未跟蹤文件中HEAD
    • 因爲y.y是(因爲HEAD~
    • 工作樹,因爲master HEAD沒有更新上述工作樹
當觸摸

這意味着y.y保留在HEAD的第二個結帳處。

A git clean後第二個git checkout master可以幫助。

2

我猜測了一下,但最初我相信你在提交f065234的「分離頭部」模式,這是分支名稱master指向的提交。因此git log --oneline告訴你,提交和它的兩個祖先。

無論出於何種原因,在提交時,您(或您所做的)刪除了文件y.y

首先,讓我們進入該狀態。

$ cd /tmp; mkdir repo; cd repo 
$ git init 
Initialized empty Git repository in /tmp/repo/.git/ 
$ echo 'first file x.x' > x.x 
$ git add x.x 
$ git commit -m 'init commit' 
[master (root-commit) 63ddf00] init commit 
1 file changed, 1 insertion(+) 
create mode 100644 x.x 
$ echo 'second file x.y' > x.y 
$ git add x.y 
$ git commit -m '2nd commit' 
[master 62cb693] 2nd commit 
1 file changed, 1 insertion(+) 
create mode 100644 x.y 
$ echo 'third file y.y' > y.y 
$ git add y.y 
$ git commit -m 'add y.y' 
[master b4c61d1] add y.y 
1 file changed, 1 insertion(+) 
create mode 100644 y.y 
$ 

現在我們只需要 「分離HEAD」:

$ git checkout --detach master 
Note: checking out 'master'. 

You are in 'detached HEAD' state. You can look around, make experimental 
changes and commit them, and you can discard any commits you make in this 
state without impacting any branches by performing another checkout. 

If you want to create a new branch to retain commits you create, you may 
do so (now or later) by using -b with the checkout command again. Example: 

    git checkout -b new_branch_name 

HEAD is now at b4c61d1... add y.y 
$ 

接下來,我們刪除y.y,並要求混帳切換到分支master。我們將看到D狀態文件y.y,就像你做的事:

$ rm y.y 
$ git checkout master 
D y.y 
Switched to branch 'master' 
$ 

我做的原因上面的「分離HEAD」的步驟是,如果我沒有,我會體驗到不同的輸出。我可以通過只重複git checkout master命令,現在告訴你:

$ git checkout master 
D y.y 
Already on 'master' 
$ 

在這兩種情況下,雖然,這裏的事情是,Git是已經在提交你問的。因此它不必觸摸工作目錄 - 所以它不需要。

但是別的什麼!實際上,這是我的rm y.y命令。我刪除了該文件。 Git可以看到文件丟失,所以它通過D行宣佈。

接下來,你問的git檢查出先前的承諾(HEAD~1又名master~1,這是你的倉庫,我的承諾04a734062cb693,如上面的git commit輸出看到的,因爲我不是你,我的文件可能包含不同的數據,等等:我的存儲庫是不同的,這使得我所有的SHA-1不同)。

要切換到提交,git必須刪除文件y.y:該文件在提交f065234而不是提交04a7340。該文件已經丟失,這使得git的工作非常簡單:它通過無所事事「去除」不存在的文件。

從這點上來說,如果你問的git檢查出提交master -i.e.,提交f065234 -git將不得不把文件y.y工作目錄。你在一些額外的步驟(首先檢查b6ca522,其中也沒有y.y,然後檢查f065234),但你到達那裏,這意味着git從底層存儲庫中重新提取y.y,把它放在你的工作目錄中。


注:這裏要小心,git checkout有不同的使用模式,可以輕鬆地可以擦除工作。該文檔中的模式拼寫爲git checkout commit -- path,例如git checkout HEAD -- x.x。不幸的是,(在我看來)很容易意外地調用這種其他的使用模式。下一節只是約git checkout commit,而不是git checkout commit -- path。在此之後,我會插入一個關於path版本的簡要部分。


作爲一般規則,任何犯SHA-1你在-是否脫落,或通過分支名稱是什麼,當你問它來檢查了另一個承諾Git是看什麼文件需要通過比較兩個提交,在工作目錄中添加,刪除或修改。 (如果兩次提交相同,結果很簡單:沒有文件需要更改,請仔細考慮下面的第一條評論:如果你已經在1234567和你git checkout 1234567,沒有文件需要更改,所以git checkout簡單地做git status。)

任何工作目錄文件,不是需要任何更改,git單獨離開。

對於任何文件確實需要在某種方式進行更改,git檢查,看看你是否會失去工作。一些明顯的失去工作的方式包括這些(有更多,但我會列出這些):

  • git必須刪除文件,但你已經編輯它(它不符合當前的提交,太多少於目標提交,它表示刪除它)。
  • git必須用不同的版本替換文件,但你已經編輯它。
  • git必須創建文件(它在目標提交中,但不是當前提交),但是你自己創建了它,其內容不同於git將要放入的文件。

在這些情況下,git checkout將因錯誤而停止,除非你給它--force標誌。

但是,在許多情況下,許多工作目錄文件不需要更改。例如,在上面,我可以從master切換到master~1master~2而不改變文件x.x:這三個修訂版本都是一樣的。

這意味着git會允許我修改x.x,甚至完全刪除它,還是看看一些其他的承諾:從開關到mastermaster~1 /或後不需要進行任何更改x.x。如果我做了這些簽出,git會打印任何這樣的文件的單行狀態消息,其中D表示它在工作樹中缺失,或M表示它在工作樹中被修改(相對於現在檢查-out commit或branch)。

(無論這是否是最初的設計,人們都喜歡它,它可以讓你開始改變一堆文件,然後意識到你應該一直在另一個分支上工作,所以你git checkout另一個分支。只要沒有任何更改需要銷燬切換,git的開關,讓你的變化,所以現在這些變化都準備在其他分支去)


上述所有正在討論如何git checkout。當你要求它簽出一個特定的提交(「分離HEAD」模式)或分支(「不分離」)時會表現出來。在這種模式下,您只需調用git checkout,並且只有一個附加參數,它應該是分支名稱或其他提交說明符:git checkout HEAD^git checkout master等等。

不管是什麼原因,git 使用git checkout命令從提交中提取特定文件(通過索引/暫存區寫入提取)。要調用這個模式,你應該給一個字面雙破折號--分離git checkout兩個或多個參數:

git checkout HEAD -- x.x x.y 

這告訴git checkout,關於--左側的東西是犯符,即其中在存儲庫中查找 - 而右邊的東西是文件路徑,它應該丟棄在右側命名的路徑上正在進行的任何工作,用從左側提交中提取的版本替換它們。

換句話說,如果你已經開始編輯x.x並決定要「取消編輯」,以使它看起來像它在HEAD確實犯,你檢查出的x.x的HEAD版本到文件x.x 。或者,如果要將x.x的前一個(HEAD^HEAD~1)版本獲取到工作目錄並進行階段提交,則可以使用git checkout HEAD^ -- x.x

這種形式顯然比git checkout commit(它試圖避免破壞你的工作)更危險。不幸的是,git checkout不是要求--部分。此外,如果您不提供它,則提交說明符默認爲HEAD。所以:

git checkout -- x.x 

的意思是「請揍我發來文件x.x的變化,也是如此:

git checkout x.x 

因爲x.x不是提交或分支同樣的名稱:

git checkout . 

命名一個路徑,但這次路徑是「當前目錄」,所以這個clobbers所有的文件都工作在一個重新在當前目錄中,或者遞歸地在它下面的任何地方!

(如果混帳用於「退房特定文件」不同的命令VS它可能是好的,「退房給出提交-ID」,使其更難意外揍的工作。)


你做不問,但我也會在這裏包括這個:「分離HEAD」和「在分支上」之間的區別實際上是非常簡單的。在.git目錄中查看;你會發現一個名爲HEAD的文件。當您在諸如master的分支上時,HEAD的內容是ref: refs/heads/master。當你分離時,內容是一個原始的SHA-1像b4c61d1692f750607a821aa53788e3a7ce5d1199(git通常顯示你的縮寫版本)。簡而言之,當你在分支上時,git從分支名稱中獲取原始SHA-1,分支名稱在HEAD文件中;當你分離時,git將原始SHA-1直接存儲在HEAD文件中。

還有一個關鍵區別,它適用於創建新提交提交。如果HEAD有一個原始SHA-1,git將新提交的SHA-1寫入HEAD。如果HEAD改爲ref: refs/heads/branch,git會將新提交的SHA-1寫入分支映射文件,而文件HEAD保持不變。爲了提高效率,分支映射文件有時會有所不同,儘管當前新的提交始終創建或更新名爲.git/refs/heads/branch的文件。

+0

令人難以置信的幫助,但我的經驗不同於你說的一些。例如,如果我將一行添加到'xx'並提交,然後將另一行添加到'xx'並再次提交,然後添加第三行(unstaged),我不會收到警告,但我確實得到了奇怪的行爲:''最後一次提交的checkout'重新應用**我的本地更改(!?!?),提交之前提交的checkout提供了一個錯誤(爲什麼?)。 '結帳.'無聲地刪除我的本地暫停更改,沒有警告,無法恢復。我發現'git'是令人難以置信的違反直覺的。 – Fixee

+0

您已經修改了文件,沒有對其進行暫存,並要求查看當前的提交。 「當前提交」和「當前提交」有什麼區別?至於'git checkout .',那不幸的是完全不同(我有時希望git使用不同的*命令*來完成這個完全不同的行爲):它要求git強制覆蓋來自命名提交的目錄'.'(我將編輯有點在此)。 – torek

相關問題