.git文件夹_Git幸存者指南
> Learn how to use Git to version control a cake recipe… and other things like code!
或如何用Git烤蛋糕
Git很難。 Git令人生畏。 學習曲線很大。 作為軟件工程師,這至關重要。
Git是用于版本控制的行業標準。 這是我們大多數人在學?;蚓幋a訓練營中都不學的東西。
我在新手訓練營期間就第一次聽說了Git,并完成了一些教程,但是直到找到工作并開始與其他開發人員合作,我才真正使用它。 實際上,我看到新的開發人員無時無刻不在出現,并且在學習Git方面遇到困難。 因此,如果您感到困惑,您并不孤單。
我討厭每分鐘學習如何使用Git。 很難為絕對的初學者找到資源,而我發現的少數資源寫得不好或不太清楚。 他們通常會假設您可能沒有(我沒有)一定水平的知識。 因此,我想為準備開始從事第一項技術工作的人員或已經從事該工作并像我一樣擁有" oh sh * t"時刻的工程師提供資源。
我不是Git專家。 但是我確實知道一些基礎知識,這些基礎知識是通過從開發人員的經驗和投入中學到的,這些知識使我能夠與同事進行協作,因此我可以真正接觸到自己的專長:編寫代碼。 我將在這里學到的東西也希望能幫助您達到自己的專長。
無論如何,Git到底是什么?
Git是您在計算機上安裝的軟件。 如果尚未安裝,請進行安裝。
使Git與iTunes或Minesweeper(甚至比其功能更多)不同的原因在于Git沒有圖形用戶界面(或GUI)。 GUI徹底改變了計算,使Steve Jobs和Bill Gates變得富有。 在使用GUI之前,您必須通過命令行與程序進行交互。 由于Git沒有GUI,因此您也可以通過命令行與它進行交互(至少有時會在以后進行介紹)。
$ git checkout -b [branch name] origin/[branch name]
當您在教學網站上看到類似的內容時,這是一個命令行命令,可以在Mac的終端機,Windows的命令提示符或Linux的Shell中運行。
因此,這是人們想知道的其中一件事:$代表美元登錄終端前的所有垃圾。 這是我的:
Kevins-MacBook-Pro-2:~ kevinmiller$
在教程中看到$時,只需在其右側輸入內容即可。 []或{}或<>表示您應該被視為自己的信息中的一員。 輸入終端后,該命令的外觀如下:
Kevins-MacBook-Pro-2:~ kevinmiller$ git checkout -b master origin/master
稍后我們將詳細討論命令。 接下來的邏輯問題:
但是它是做什么的呢?
好問題。 Git是用于源代碼控制(有時稱為版本控制)的工具。 它跟蹤文件中的更改,并允許多個人在同一文件或一組文件上進行協作。 如果您曾經有多個名為" Paper-Draft.docx"," Paper-Final.docx"," PaperFinal2.docx"," PaperFinalFinal.docx"," PaperTHISISTHERIGHTONE.docx"的Microsoft Word文件,那么您就知道需要進行源代碼控制。 您可以看到,如果您有五個,五十個,或者對于大型公司而言,成千上萬的人在同一文檔上工作,那怎么可能真正失控。 Git通常用于軟件開發,但可以用來跟蹤幾乎所有文件集中的更改。
聽起來不錯……它是如何做到的?
Git為您的工作拍攝快照,稱為提交。 回到我們的Microsoft Word Nightmare Analogy(?),您可以想到一次提交,就好像您打印了每個版本的學期論文并將其歸檔在文件柜中一樣。 Git對存儲庫中的每個文件執行此操作。 每次文件更改時,都會創建一個新副本。 存儲庫只是" Git為您跟蹤的所有文件"的花哨詞。
多個人如何在不互相踩腳的情況下進行協作? 人們通常會在自己的部門工作。
根據Atlassian
分支代表獨立的發展線。 分支充當編輯/階段/提交過程的抽象。 您可以將它們視為請求全新的工作目錄,暫存區和項目歷史記錄的方式。
有點稠密。 想象一下,您與一位合伙人開始了學期論文。 您負責撰寫一個主題,而您的伴侶負責撰寫另一個主題。 您是一起編寫介紹段落的,但是現在每個人都需要獨立工作。 你們兩個都將從相同的文件" Paper-Intro.docx"開始,但是每個人都將擁有自己的文件柜! 您將能夠獨立工作并跟蹤自己的版本,但是兩者都是在同一時間開始的。 在工作時,每次獲取要保存(提交)的版本時,都會將其打印出來并保存在文件柜中。 您的伴侶將對他們的文件柜做同樣的事情。
許多教程使用樹隱喻來描述分支。 您可以將原始分支(稱為主分支)視為樹干。 樹上的每個分支都來自樹干,但它自己分裂。 但是,我喜歡將其視為高速公路-假設您有一條只有一條車道的高速公路。 這是您的主分支。 如果創建另一個分支,則高速公路將變為兩車道高速公路。 當您更改分支機構時,就像車道分支到了自己的出口一樣。 您可以開車去做任何您想做的事,因為它與公路分開。 最終,它將合并回到高速公路上。
由于您已記錄了所做的所有更改(如果選擇提交),因此可以輕松地進行協作,回到舊版本,合并版本等。無限的可能性。 一個項目很可能具有多個分支或多個系列的版本。 隨著開發的進行,這些分支將全部合并在一起以創建最終產品。
信不信由你,這是Git的基礎。 理解它的最好方法就是使用它。 所以,讓我們做一個蛋糕! 好吧,我們將為蛋糕制作購物清單。 我強烈建議您在自己的計算機上進行以下操作。 這樣做會更有意義。
但是如何Git?
首先,我們需要建立一個存儲庫。 請記住,這只是計算機上的一個文件夾(及其子文件夾),文件在其中存放并由Git跟蹤。
我在計算機上創建了一個名為Shopping List的文件夾。 進行相同的操作,在可以找到它的地方。
好的,我們有文件夾。 至此,我們還沒有列表,也沒有Git。 因此,讓我們將文件夾放入Git存儲庫中。 在命令行上,運行以下命令:
$ cd
看看我在那里做什么? 我使用了我們之前提到的速記。 這實際上是我的命令行上的樣子:
Kevins-MBP-2:gittutorial-ios kevinmiller$ cd /Users/kevinmiller/Developer/Shopping List
這是做什么的? 它將當前目錄(cd)從舊目錄(當前工作項目)更改為我們想要Git存儲庫的目錄。 因此,一旦進入,請運行以下命令:
$ git init
這將初始化一個Git存儲庫。 如果您導航到系統上的該文件夾,則會看到一個名為.git的新文件夾,Git將在該文件夾中跟蹤您的項目,在本例中為我們的購物清單。 注意:如果看不到.git文件夾,則可能必須啟用查看系統上的隱藏文件夾。 通常,以"。"開頭的文件和文件夾 隱藏起來是因為它們很重要,如果您不知道自己在做什么,很容易搞砸。
好的,現在讓我們列出購物清單。 讓我們保持簡單,并創建一個名為ShoppingList.txt的.txt文件(如果需要,可以使用任何文本編輯器或命令行)。 讓我們添加三種成分:
Eggs
Flour
Sugar
現在我們有了蛋糕的基本原料。 可能不花哨,但仍然可能很好。
記住,為了清楚和易于理解,我們正在制作一個簡單的購物清單,但這通常是代碼……Git對兩者都起作用!
保存文件并輸入:
$ git status
這是您應該看到的:
On branch master
No commits yet
Untracked files: (use "git add ..." to include in what will be committed) ShoppingList.txt
nothing added to commit but untracked files present
(use "git add" to track)
Kevins-MBP-2:Shopping List kevinmiller$
到目前為止,一切都很好! 如果您看到除此以外的其他內容,請放棄所有希望并放棄嘗試。 開玩笑。 您可能在錯誤的目錄中,也許尚未安裝Git,或者您忘記保存文件。
在解開以上內容之前,我們先討論一下GUI。 Git有幾個不錯的GUI包裝器。 我使用SourceTree并強烈推薦它。 但是,您不必擔心命令行。 一切都可以從命令行完成,在某些時候,您將不得不使用它。 GUI可以完成很多工作,但不能完成所有工作。 這實際上是個人喜好問題。 最終,一旦您知道要使用Git做什么,就無關緊要(通過命令行或GUI)。
在上方,我們詢問了我們的狀態,并收到Git的回復。 它告訴我們我們的分支機構(我們的快照歷史,還記得嗎?)。 這就說得通了。 主文件是第一個分支的默認名稱,因為它是"主副本"。
現在它說"沒有提交"。 這也是有道理的。 我們尚未告訴它進行任何提交。
這就是它變得有趣的地方。 它說:
Untracked files: (use "git add ..." to include in what will be committed)ShoppingList.txtnothing added to commit but untracked files present (use "git add" to track)Git注意到我們制作了一個新文件-這就是我們制作的文件。 涼! 這也告訴我們尚未為我們跟蹤此文件。 我們希望它做到這一點。 對我們來說幸運的是,它告訴我們如何使用$ git add 來執行此操作…現在我們知道這意味著$ git add ShoppingList.txt。 繼續做吧。
Cool。 怎么辦? 再次執行
On branch masterNo commits yetChanges to be committed: (use "git rm --cached ..." to unstage)new file: ShoppingList.txt好! 現在,我們要進行一些更改! 是。 我們從沒有文件轉到了包含3個項目的ShoppingList.txt文件。 Git告訴我們下一次提交的內容。 但是我們仍然沒有告訴它要提交。 來做吧。
$ git commit -m "Created shopping list for cake"
-m是什么? 這是輸入提交消息的快捷方式。 永遠不要在沒有提交消息的情況下進行提交,而永遠不要在帶有" WIP"之類的通用提交消息的情況下進行提交。 您希望簡明扼要,但要在提交消息中進行描述。 看起來似乎有些痛苦,但是請考慮一下:我們使用Git的全部原因是為了跟蹤文件中的更改。 如果(當您)必須回顧文件的歷史記錄或瀏覽他人的工作,則清除提交消息至關重要。 請參閱本文,以獲取編寫提交消息的最佳實踐的示例。
恭喜你! 您是第一次提交。 讓我們做更多。
那個蛋糕有點無聊。 讓我們添加一些澆頭并將其分類。 我們也想將面粉改為黃油,因為我們家里已經有面粉了。 (您可以將下面的列表想象為代碼嗎?每個"配方"都可以是一個函數。)
--- Cake ---EggsButterSugar--- Toppings ---StrawberriesRaspberriesChocolate好吧,讓我們做和以前一樣的事情:
$ git statusOn branch masterChanges not staged for commit: (use "git add ..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory)modified: ShoppingList.txtno changes added to commit (use "git add" and/or "git commit -a")所以現在我們有了一些不同。 "沒有為提交而進行的更改……"是什么意思? 這表示我們進行了一些更改,但尚未提交或"保存"。
除了簡要介紹Git的工作方式之外,我還提到過:Git保留整個項目的快照或提交。 如果您制作每個文件的副本,并且在您的項目中擁有成千上萬的提交和成千上萬的文件(我目前的項目有2,446個),那么它將變得非常快。 那么Git如何處理呢? 如果有更改,它只會創建文件的新副本。 否則,它將引用文件的舊副本。 在這里,它將文件的最新副本與此新副本進行比較,然后說:"嘿! 這些是不同的,您想做什么?"
讓我們看看這些變化是什么…
diff --git a/ShoppingList.txt b/ShoppingList.txtindex b61f001..774565b 100644--- a/ShoppingList.txt+++ b/ShoppingList.txt@@ -1,3 +1,9 @@+--- Cake --- Eggs -Flour+Butter Sugar++--- Toppings ---+Strawberries+Raspberries+Chocolate這使我們可以看到上一次提交與現在提交之間的差異。 它用-顯示刪除的行,以及我們用+添加的行。暫時不要擔心頂部的內容。 這對您對Git概念的一般理解很重要,但并不重要。
現在,我們必須決定所做的更改將包含在下一次提交中。 這稱為暫存。 登臺是您選擇要提交或"保存"的更改的地方。 暫存實際上并沒有"保存"任何內容,您必須致力于做到這一點。 如果您一次對多個文件進行了更改,則可以選擇要在此處進行的更改。 在很多情況下,您可能不想包含所有更改,但現在,我們希望包含所有更改。
$ git add ShoppingList.txt$ git commit -m "Added ingredients for fruit torte, removed flour"太棒了! 現在購物清單看起來不錯。 但是在我們購物之前,保羅·好萊塢和瑪麗·貝瑞想在購物清單中添加一些物品。 讓我們為他們創建新的分支,以便他們可以將項目添加到列表中。
(在這里播放……我們將自己做所有這一切,但是想像您正在與需要處理同一文件的同事進行真正的協作。)
讓我們為Paul創建一個分支,為Mary創建一個分支:
$ git branch pauls-branch
$ git branch marys-branch
好吧! 現在,我們已經為Paul和Mary創建了分支機構,以便分別工作。 盡管它并不完全準確,但是您可以將創建分支視為創建項目的新副本。 然后,Paul和Mary將對自己的副本而不是主副本(分支)進行更改。 他們(我們)將做出改變。 首先,執行以下操作:
$ git branch
這是您應該看到的:
marys-branch* masterpauls-branch我們有三個分支:我們剛剛創建的兩個分支和最初的一個分支,即master。 從本文開頭繼續我們的高速公路隱喻,我們現在有了一條三車道的高速公路。 這些車道之一即將駛出。
因此,讓我們檢查一個分支并開始制作購物清單:
$ git checkout pauls-branch如果需要,請再次運行$ git branch,您會看到星星現在在pauls-branch上。 檢出分支使其成為您的活動工作副本。 您對文件所做的任何更改都將提交到該分支。
好的,該添加一些東西到Paul的購物清單中了。 打開您的購物清單并進行以下更改:
--- Cake ---EggsUnsalted ButterSugar--- Toppings ---BlackberriesRaspberriesChocolate保羅自命不凡,喜歡無鹽黃油,所以他換了黃油。 他還把草莓換成了黑莓。 保存文件,然后暫存并提交這些更改。
$ git add -A
這是什么? 這只是暫存所有已修改文件的快捷方式。 在Git中,有多種方法可以執行相同的操作。
$ git commit -m "Added ingredients for summer fruit genoise"
我們只想要一個購物清單,所以讓我們將其合并為一個清單。 首先結帳的主人(請記住,這是主要的高速公路)。
$ git checkout master
當您簽出其他分支時,Git實際上會自動交換目錄中的文件。 如果看不到文本文件中的更改,請關閉然后重新打開。
現在,我們將Paul的分支機構合并回我們的原始購物清單:
$ git merge pauls-branch
還不錯吧? 現在,保羅的更改應反映在我們的清單中! 打開并簽出。 我們來看看Mary的分支,并向其中添加一些內容。
$ git checkout marys-branch
打開購物清單。 您會看到它回到了我們分支的狀態。 讓我們對瑪麗進行更改。 (將草莓換成藍莓。)
--- Cake ---EggsButterSugar--- Toppings ---BlueberriesRaspberriesChocolate好。 保存文件,然后暫存并提交更改。
$ git add -A$ git commit -m "Added ingredients for blueberry cake"
好! 讓我們將其合并到master分支中。
$ git checkout master$ git merge marys-branch
哦! 出問題了!
CONFLICT (content): Merge conflict in ShoppingList.txtAutomatic merge failed; fix conflicts and then commit the result.那這是怎么回事? 您可能已經猜到了,這是故意的。 這稱為合并沖突,就像生活中的沖突一直在發生。
當我剛開始時,聽到"合并沖突"一詞使我感到恐懼。 讓我們嘗試理解它,以減少恐懼感。 是什么導致合并沖突? 根據Github的幫助,"合并沖突會在合并具有競爭提交的分支時發生。" 讓我們稍微打開一下包裝。 保羅和瑪麗都同時分支,這意味著他們倆都從相同版本的購物清單開始。 保羅做了一些更改,瑪麗做了一些更改。 我們將Paul的更改合并到我們的主購物清單中,現在我們嘗試將Mary的版本合并到其中。
即使這不是我們開始使用的原始文件,Git仍會嘗試進行更改。它知道在第6行上我們正在嘗試更換草莓->藍莓,但我們用黑莓代替了草莓,因為保羅改了。我們有“競爭提交”。 Git不知道該怎么辦,需要人工指導。那就是我們進來的地方。
打開您的ShoppingList.txt文件。 您會在其中看到一些新內容:
--- Cake ---EggsUnsalted ButterSugar--- Toppings ---<<<<<<< HEADBlackberries=======Blueberries>>>>>>> marys-branchRaspberriesChocolate<<<<<<
如果我們想說"不,保羅,黑莓現在太貴了",我們將刪除黑莓。 但是,我們將繼續保留兩者。 這就是Git不僅更換黑莓->藍莓的原因。 我們可能想要兩者-我們都這樣做。 刪除沖突標記,編輯文件,然后保存。
現在您可能會問自己,為什么黃油不存在沖突? 瑪麗的樹枝上有普通黃油,而保羅的樹枝上有無鹽黃油? 好吧,瑪麗沒有嘗試換黃油,所以吉特選擇了保羅的零錢,這已經掌握了。
--- Cake ---EggsUnsalted ButterSugar--- Toppings ---BlackberriesBlueberriesRaspberriesChocolate贊! 我們已經解決了沖突。 但是,我們仍然必須完成合并。 記住,上面說修復沖突,然后提交結果。
$ git add -A$ git commit -m "Merged marys list"
您剛剛解決了第一次合并沖突! 現實世界中的合并沖突將比這個簡單的示例更為復雜,但是基本概念是相同的。
當一切順利時,Git工作流程非常簡單:
遠程與本地
我們在本教程中所做的所有操作都是本地的,這意味著我們的計算機會跟蹤我們計算機上的所有這些文件,而這些文件在其他任何地方都不存在。 如果您要與同事合作,并且想做一些非常合理的事情(例如使用不同的計算機),則此功能不是很有用。 所以你會怎么做? 使用遠程存儲庫在線跟蹤這些更改。 通常,它會托管在BitBucket或GitHub之類的網站上,這意味著您的代碼庫(在我們的情況下,我們的購物清單)將存儲在其他人的計算機上。
因此,如果代碼存儲在其他位置,我們如何對其進行更改? 首先,我們需要克隆該存儲庫。
克隆說明因存儲庫的托管位置,身份驗證類型等而異,因此,我將由您自己決定。 什么是克隆? 顧名思義,克隆存儲庫會在您的計算機上復制一個副本。 擁有此副本后,就可以對其進行處理-像我們上面討論的那樣進行更改。
對副本進行更改后,它們僅在計算機上本地存在。 您如何將它們發送到遠程存儲庫? 有一些命令。 這些絕不是詳盡無遺的,并且有許多不同的情況需要不同類型的推拉,但這將使您對該概念有基本的了解。
推送是指對所做的更改并將其推送到遠程(代碼庫的存儲位置)。 還記得瑪麗對蛋糕食譜的更改嗎? 之后,她需要將自己的更改推送到遙控器,如下所示:
$git push origin marys-branch
如果分支尚不存在,則必須使用:
git push -u origin marys-branch
-u是–set-upstream的縮寫,它指示Git創建"上游"或遠程分支。 瑪麗·貝瑞(Mary Berry)當然是知道的,因為她是Git專家。
拉就是拉其他人對您的本地計算機所做的任何更改。 想象一下,保羅想查看主購物清單的新變化,自從克隆存儲庫以來,該更新已更新:
$ git pull master 獲取此后所做的所有更改,并更新本地分支。
我認為,pull request是一個非常令人困惑的名稱。 假設瑪麗負責購物清單代碼存儲庫。 保羅脫離了大師,進行了一些更改,并將這些更改推到了遠端。 他現在希望將這些更改合并到母版中。 好吧,由于瑪麗負責并需要批準這些更改,因此他提交了一個稱為拉取請求或簡稱PR的內容。 他要求瑪麗將其分支機構拉到主分支機構。 看到? 我認為這很麻煩。 他真的是要求瑪麗將其分支機構合并為大師。
通過諸如BitBucket或Github之類的服務發出拉請求。 除了托管您的存儲庫外,他們還為同事提供了一個提交和審閱彼此的請求請求的地方(稱為代碼審閱)。 瑪麗只會登錄Github來查看Paul的公關。 她將看到他要進行的更改,并有機會在批準或拒絕之前發表評論并請求更改。
Git:最終疆界
在現實世界中,您的項目將比這更復雜。 您將擁有更長的文件,更多的文件和更多的分支(希望不是太多)。 通常,將有一個主分支,一個開發分支和多個功能分支。 master分支通常代表生產中的代碼(例如,實時網站或iTunes Store中的應用程序)。 Develop表示正在進行的代碼。 開發人員通常會針對他們正在使用的每個功能從開發中分離出新的分支,然后在完成后將其合并回開發中。 當一個新版本經過測試,穩定并且可以發布時,develop將合并到master中。
信不信由你,Git的工作流程在上面的簡單購物清單和現實世界中幾乎相同。 讓我們看一下我們所做的工作流程,并將其與實際工作流程進行比較。
工作需要完成。 在我們的案例中,我們需要添加蛋糕的配料。 一個真實的示例可能是在您的數據服務對象中添加一種方法以連接到API
有人開始工作。 上面,保羅和瑪麗做了分支以添加成分。 在現實世界中,您可能會脫離開發并創建一個名為"功能/集成所有食譜-API"的分支
進行更改。 通常,這意味著代碼已編寫。 例如,保羅在餅干食譜中添加了成分。 在現實世界中,從API獲取配方可能類似于以下功能:
func getRecipesWith(ingredients: [String], success: @escaping (([Recipe]) -> Void), failure: @escaping ((APIError) -> Void)) { let endpoint = "(DataStore.ingredientFilterEndpoint)" requestManager.request(withEndpoint: endpoint, method: .GET, params: [DataStore.ingredientsKey: ingredients.commaDelimitedComponents], success: { responseObject in guard let json = responseObject as? JSON, let recipeList = RecipeList(json: json), let recipes = recipeList.recipes else { failure(APIError(failingURL: endpoint, message: "Cannot parse Recipe from JSON")) return } success(recipes) }, failure: { error in if let error = error { failure(error) } }) }變更已上演。 我們進行了本教程中的所有更改,但是如果我們編寫了一些我們不想提交的內容,例如,一個測試函數,例如:
func generateFakeRecipe() -> Recipe
我們可能選擇不上演。
更改已提交。 我們承諾要保留的更改。 保羅的作品之一是"為夏季黑莓添加了水果",現實世界中可能是"數據存儲中的添加方法可以檢索按成分過濾的配方陣列"
更改已推送。 工作完成后,將分支推送到遠程。
更改已審核。 同行審查和評論/請求更改。
更改被合并。 分支合并了!
這是有關Git的全部知識嗎? 離得很遠。 在您感到自在之前,您可能需要自己做更多的研究。 您肯定必須練習,弄糟,然后再練習一些。 盡量不要太害怕-幾乎所有內容都可以撤消。 Git非常安全。 不要害怕尋求幫助;不要害怕。 大多數開發人員都記得學習Git的感覺。
希望您能從本文中獲得我所沒有的東西:一個可以輕松理解而無需做任何假設的綜合場所,以學習Git的基礎知識。 祝您好運,編碼愉快!
(本文翻譯自Kevin Miller的文章《A Survivor's Guide to Git》,參考:https://medium.com/@kevin.thom.miller/a-survivors-guide-to-git-5cd93b13335b)
總結
以上是生活随笔為你收集整理的.git文件夹_Git幸存者指南的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++ qt qlistwidget清空
- 下一篇: dbscan聚类算法matlab_密度聚