2014-12-30 189 views
2

我最近開始使用SourceTree和Git,但我仍然對存儲/分支和工作副本文件感到困惑。我一直無法找到任何明確的東西給我。隱藏/分支/工作副本混淆

我的困惑是關於文件的工作副本關於分支和窗口。我期望的事情的工作方式是,我的文件的工作副本也將鏈接到分支。如果我要切換分支,它會在切換到新分支之前自動保存我的工作副本。如果我要切換回前一個分支,它將再次存儲當前的工作副本文件並從前一個分支中恢復這些文件。

在使用SourceTree和Git一段時間之後,它對我來說顯得非常清楚,它不是如何工作的,而且工作副本文件與您的分支完全無關,就像存儲。如果切換到另一個分支,您的選擇是手動存儲工作副本文件,放棄更改或將您的工作文件帶到新分支。

所以,我想知道的是,這是什麼理想的工作流程?假設我正在兩個不同的分支中同時開發兩個功能,並且想不斷地來回跳動。我是否需要記住在每次切換前存儲我的工作副本文件或者是否有更好的方法?

+0

*如果我要切換分支,它會在切換到新分支之前自動保存我的工作副本。如果您有未提交的更改與您正在檢查的分支發生衝突,那麼Git不會讓您這樣做。你需要「手動」存儲它們; Git不會自動爲你做。 – Jubobs

+0

好吧,知道我不只是錯過了一些東西。我猜想SourceTree中的彈出窗口詢問你是否想要放棄本地更改也應該提醒您在切換之前隱藏它們。 – Mathieson

+0

如果你從命令行使用Git,我相信你會有更好的體驗,但這只是我的看法。特別是,我不確定SourceTree是否允許您定義別名/宏。 – Jubobs

回答

1

如果我要切換分支,它會自動存儲我的工作副本,然後切換到新分支。

不! Git不會自動爲您保存本地更改。另外,如果您有未提交的更改與您正在檢查的分支發生衝突,那麼Git不會讓您檢出相關分支。您需要在檢出其他分支之前「手動」丟棄或隱藏它們。

它似乎很清楚我的工作拷貝文件是完全獨立於你的分支,就像是存儲。

是的,這有很好的理由。特別是,一個用於存儲的用例是在檢出「錯誤」分支時開始進行更改。然後,您可以通過

  • 積攢你的本地修改(從而降落在一個乾淨的工作狀態)走出困境,
  • 檢查出「正確」的分支,
  • 大跌眼鏡的是藏匿恢復您的本地更改。

說我是同時開發兩種功能,在兩個不同的分支,並希望不斷來回跳轉。我是否需要記住在每次切換前存儲我的工作副本文件或者是否有更好的方法?

是的,在切換到另一個分支之前存儲您的更改,然後彈出以前的存儲,將是正常的工作流程。如果您經常切換分支,那確實很乏味,但是如果您使用命令行中的Git,則可以定義aliases以抽取某些複雜性。

我從來沒有使用過SourceTree,但我可以想象如何存儲/檢出/彈出可能涉及很多繁瑣的鼠標點擊。不過,顯然,SourceTree 引入了一種名爲「Custom Actions」的機制,允許您定義自己的命令,including Git commands。你可能想看看它......

2

「TL; DR」部分:提防只是盲目做git stash save && git checkout ... && git stash pop


實際上有幾件你可以取笑,特別是在使用git的命令行界面時。

特別是,「當前分支」(如果有的話)只是記錄在文件中的項目(該文件包含HEAD參考,.git/HEAD)。查看該文件的原始內容,您通常會看到ref: refs/heads/master等。 (在「分離HEAD」模式下,您將看到一個原始SHA-1。)有一些低級別的git命令會更新HEAD而不做任何其他操作。

但是,大多數人主要使用git checkout來切換分支,除了正確的方法:-)來做到這一點 - 內置了一些保護。主要是,如果您有工作樹,它將拒絕切換分支「索引」(AKA緩存)修改將被這樣的交換機丟失。假設您在分支A上,並且您要求切換到分支B。結帳過程必須:

  • 得到存在於尖端的所有文件的清單提交分行A
  • 的獲取存在於尖端的所有文件的列表選項B
  • 的承諾在文件第一個不在第二個的列表中,從第二個列表中不在第一個文件的工作目錄
  • 中刪除這些文件,將這些文件添加到工作目錄中
  • 中的文件如果(且僅當)文件不同,則替換工作目錄內容[R

此外,退房時被做緩存「通過書寫」:如果文件FAB不同,的B版本的內容將首先被複制到索引/緩存,然後寫入工作目錄。

如果你已經上演(與git add)一些修改文件F,或者你有一些未上演修改F在你的工作目錄,該結賬過程將覆蓋這些階段性或非階段性變化,因此git checkout停止帶有錯誤信息。如果文件F將被刪除,那麼也會覆蓋(或者更準確地說,刪除)您的更改,因此checkout也會停止。

在另一方面,如果文件F兩個犯了同一,在checkout可以繼續:它只是離開未提交的更改上演或不分級。這就是爲什麼你有時可以,但不總是,只需git checkout你想要工作的分支。


Git的 「藏匿」(如git stash),正如你所看到的,獨立的分支。這裏的關鍵概念是每個存儲 - 你可以有多個活動 - 實際上是一個提交(或更確切地說,一組提交:兩個或三個,這取決於你存儲的內容)。但是,在您反對在分支機構上進行提交之前,我們必須再做一些區分。具體來說,「分支」一詞指的是兩三個不同的東西,在git中。

提交總是(必然)進入「提交圖」,因爲圖僅僅是由所有提交和它們的邊形成的東西。如果「分支」一詞意味着「提交圖的一部分」,這些存儲提交在分支上。但「分支」這個詞也指的是標識分支的名稱提示提交,並且在這裏,這些提交提交不會推進分支提示。 (見this post,也Jubobs,對的「分支」的多重含義的更多細節。)

git stash命令查看當前索引/緩存和工作樹的狀態,並從他們身上,使新的提交如果 - 這個「如果」事實證明是非常重要的 - 如果他們有未保存的分階段或未分階段的變化。其中一個新提交(可從其中找到其他提交)保存在特殊參考名稱stash下。儘管沒有任何新的提交被添加到當前分支,所以它們不在任何命名的分支上。從這個意義上說,它們獨立於當前分支 - 但是因爲它們是提交,所以它們具有父提交ID,並且從特定意義上講,它們直接附加到完成時提交的提交。

這對於最終用戶來說意味着什麼往往是「沒有」:你可能不在乎,也不必關心。但是,如果您曾使用git stash branch將存儲轉換爲分支,則意味着新分支將從存儲所附的提交中分離出來。 (這一點,因爲它的出現,通常是你想要什麼。)與定義,做git stash save && git checkout ... && git stash pop別名或宏


一個風險是第一步,git stash save,可以什麼都不做。如果它什麼都不做 - 如果它不在「存儲堆棧」上推送新的存儲 - 然後它成功了,並且你的別名或宏將繼續檢出其他分支,然後(嘗試)從藏匿處堆積出來。

如果在該堆棧上還有另一個(不同的)存儲器,那麼你打算在其他地方使用,那麼你只是試圖將它彈出到你剛切換到的分支中。

注意,有兩個堆疊的「如果」在這兒,必須持有,這個特定的錯誤兩個條件咬:

  • 你需要什麼都沒有藏匿,並
  • 你需要有一些現存的你不要想要彈出。

解決此問題的一種方法是使用腳本,而不僅僅是一個簡單的git別名來執行分支交換存儲序列。在腳本中,像往常一樣運行git stash,但在存儲之前和之後,檢查stash參考所解析的SHA-1(如果有)。如果這個變化,git stash save保存了一些東西,所以有一些東西可以彈出,你可以繼續做結賬和流行的順序。如果它沒有改變 - 如果前後沒有隱藏,或者如果堆棧頂部的存儲仍然在堆棧的頂部,那麼沒有任何可以彈出的東西,你應該只是做一個結帳。

還有另一個bug可以咬你這裏;看到this answer到一個有點不同的問題,其中包括一些shell代碼表示上述「只有當save實際推動某些東西」的規則彈出。

+0

一如既往,閱讀起來很不錯,但是你在可憐的OP(只通過一個GUI知道Git)的時候就會拋棄它!關於'git stash save'如何可以咬你的好點兒。我沒有意識到這一點。 – Jubobs

+1

這就是爲什麼我在頂部添加了「TL; DR」位:-) – torek