[學習] 使用git CLI並與GitHub共同運作(基礎篇)
沒事不要亂學東西!
有學習目標時,再針對需求進行學習!
鍾獻慶
2024-04-17 星期三
這幾天連續手動操作GitHub的repository,對同一個檔案,改來改去,一直搞手動存檔。如果只存一個檔就算了,問題是,當要連續存十幾個檔,或上百個檔時,每個檔案都手動存檔,這樣搞起來,很累。
發現這樣很沒有效率。
看起來還是要學一下git這個版本管理程式,並使用git來對GitHub的repository進行操作,這樣效率會比較好。
(此文不採用線性編排,是給實務使用者進行指令參考。若要學習git的基本ABC,請參考其他資料。)
前置作業
要在自己的電腦上安裝git這個版本管理軟體。
直接去Git官網下載並安裝就行。
Git官網: https://git-scm.com/
概念
使用git作為版本管理軟體,來管理專案。
什麼是專案?
在程式設計中的專案,是用一個資料夾開始,裡面放相關檔案。
例如: 建立一個GitTest在D槽下。相關檔案就放在這個資料夾下。
而使用git,就是方便管理這個專案資料夾下面的檔案。
NOTE: 在GitHub上,這個專案資料夾稱為repository。
開始使用git進行本機上的專案管理
Command: git init
進入GitTest資料夾後,使用command git init將這個資料夾初始化為Git repository。
Command:
$ git init
Result:
Initialized empty Git repository in D:/GitTest/.git/
這個command會在專案目錄(Git repository)下,建立一個.git的隱藏資料夾。裡面存放git文件。
NOTE: 如果要取消git專案管理,直接刪除這個隱藏資料夾就行。
Command: git status
使用command git status確認狀況。
$ git status
On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)
由於目前專案資料夾中沒有內容,所以就顯示這樣。
在專案資料夾下建立檔案 (開始進行專案的意思)
開始進行專案後,我們就會在專案資料夾下建立檔案。
例如: 建立一個index.html檔,裡面先不打字。
使用command git status確認狀況。
$ git status
On branch master
No commits yet
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        index.html
nothing added to commit but untracked files present (use "git add" to track)
顯示index.html這個檔案在Untracked files的列表中。
Command: git add [file]
使用command git add [file]可以對檔案進行追蹤(track)
$ git add index.html
按下Enter後,並不會顯示資訊。
需使用command git status來確認狀況。
$ git status
On branch master
No commits yet
Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   index.html
這時Changes to be committed的檔案就新增了一個index.html
NOTE: 若嫌一個檔案一個檔案慢慢加很慢,可以用git add --add或git add .,一次全部加入。
Command: git rm –cached 
若要取消這個檔案列於Changes to be committed
就使用command git rm --cached <file>
$ git rm --cached index.html
rm 'index.html'
使用command git status來確認狀況。
$ git status
On branch master
No commits yet
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        index.html
nothing added to commit but untracked files present (use "git add" to track)
使用command git add對檔案進行追蹤(track)。
$ git add index.html
使用command git status確認狀況。
$ git status
On branch master
No commits yet
Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   index.html
Command: git log
使用command git log確認有沒有log檔。
$ git log
fatal: your current branch 'master' does not have any commits yet
雖然有做git init,但還沒commit,所以還沒有log檔。
使用command git commit -m "[description text]來進行commit。
$ git commit -m "git init"
[master (root-commit) ec13f26] git init
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 index.html
使用command git config --global --list確認user.email跟user.name
使用command git config --global --list可以看到user.email跟user.name的值。
若要進行comment動作,這兩個需要有值,git需要知道是誰要進行commit的動作。
$ git config --global --list
user.email=[value of user e-mail]
user.name=[value of user name]
使用command git config --global user.email "[value of user e-mail]"可以修改user.email的值為[value of user name]。
使用command git config --global user.name "[value of user name]"可以修改user.name的值為[value of user name]。
$ git config --global user.email "GOOD@gmail.com"
$ git config --global user.name "GOOD"
$ git config --global --list
user.email=GOOD@gmail.com
user.name=GOOD
來做個小測試:
將user.email跟user.name的值都設定為空白""。
$ git config --global user.name ""
$ git config --global user.email ""
$ git config --global --list
user.email=
user.name=
credential.helper=store
此時將無法進行commit,git會問”你是誰?”,並提供修改user.email跟user.name的方式。
$ git commit -m "commit test"
Author identity unknown
*** Please tell me who you are.
Run
  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"
to set your account's default identity.
Omit --global to set the identity only in this repository.
fatal: empty ident name (for <>) not allowed
另外,使用command git log確認有沒有log檔。如果有的話,就會看log檔內容。
$ git log
commit ec13f26c40ab4c962dc180d7bbf704c84cd41d41 (HEAD -> master)
Author: [value of user name] <[value of user e-mail]>
Date:   Wed Apr 17 21:57:09 2024 +0800
    git init
去看.git/refs/heads/master這個檔案,也會看到master的值。
$ cat .git/refs/heads/master
073eaa43a0a0251b4cf6a25f8e66464268401209
$ git log
commit 073eaa43a0a0251b4cf6a25f8e66464268401209 (HEAD -> master)
與GitHub一起使用
在GitHub上建立repository
在GitHub上建立repository,名稱,例如: RubyOnRailsTest
在.gitignore欄位選擇合適的template,這個選項是方便忽略不要進行版本管理的檔案。當然,也可以自己手動寫入要忽略不進行版本管理的檔案。
使用git去複製(clone) GitHub上面的repository
打開本機的CMD git bash,進去目標專案資料夾GitTest02。
使用command git clone [GitHub提供的link]將GitHub上RubyOnRailsTest的repository裡面的檔案全部下載到GitTest02資料夾下面的RubyOnRailsTest資料夾裡面。
$ git clone [GitHub提供的link]
Cloning into 'RubyOnRailsTest'...
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (5/5), done.
NOTE: 使用clone的好處是,它會自動幫本機跟GitHub的repository設定連線。
NOTE: 當完成git clone的動作,在本機的GitTest02資料夾下面的RubyOnRailsTest資料夾名稱可以改變。不會影響後續的git push動作。
使用command git push,將本機上面的檔案上傳到GitHub的repository裡面
當本機的專案資料夾,新增一些檔案或修改檔案後,並commit完後。
使用command git push,將本機上面的檔案上傳到GitHub的repository裡面。
$ git push
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 20 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 288 bytes | 288.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To [GitHub的repository]
   655304e..23825a3  main -> main
NOTE: 這個動作會要求,帳號及密碼。如果已經設定過,就不會顯示這個要求。
NOTE:
剛上傳完後,本機跟GitHub上面的資料內容就都一樣了。
這時候,如果再進行git push的動作,則會顯示Everything up-to-date,表示兩邊檔案內容都相同,不用進行動作的意思。
$ git push
Everything up-to-date
使用command git pull,將GitHub的repository上面的新增檔案或修改下載到本機的repository裡面
當GitHub的專案資料夾,新增一些檔案或修改檔案後,並commit完後。
使用command git pull,將GitHub的repository上面的新增檔案或修改下載到本機的repository裡面。
$ git pull
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 922 bytes | 46.00 KiB/s, done.
From [GitHub的repository]
   23825a3..8fa7a3f  main       -> origin/main
Updating 23825a3..8fa7a3f
Fast-forward
 Test.rtf | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
關於git
gitis a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.git官網: https://git-scm.com/
git logo:
git雜項資訊
以下,是整理中的資料,有許多是未完全,但仍然可供提示一些查詢跟學習方向。就留在這裡,供參考。
分散式的版本控制系統 (distributed version control system)
何謂版本?
當我們對repository裡面的檔案進行新增、修改、刪除等動作時,每次的一個(組)動作,就造成一個repository的新版本。
git跟其他的版本控制系統有什麼不同?
git只在乎檔案內容,不在乎資料夾或檔案名稱。是個內容追蹤軟體。
既然git只在乎檔案內容,不在乎資料夾或檔案名稱。那檔名存在哪裡?
存在tree的物件中。
有些版本控制軟體是紀錄每次的檔案。每多一個版本,就是所有檔案都copy。
而git是拍快照(snapshot),把資料夾結構拍下來。只要檔案沒有變更,就不會存檔,而是記錄前一次檔案的連結。
git add --all vs. git add .
在git 1.x版的時候
| 使用參數 | 新增檔案 | 修改檔案 | 刪除檔案 | 
|---|---|---|---|
| --all | O | O | O | 
| . | O | O | X | 
在git 2.x版的時候
| 使用參數 | 新增檔案 | 修改檔案 | 刪除檔案 | 
|---|---|---|---|
| --all | O | O | O | 
| . | O | O | O | 
git add --all,不管在專案的哪一層資料夾執行,都有效果。
git add .,只會對目前指令下達的這一層資料夾及其子資料夾,有效果。
REF:
YouTube: 你知道 Git 是怎麼一回事嗎
https://youtu.be/LgTf7m5B0xA?t=257
什麼是SHA1演算法?
git裡面那個亂亂的碼,是使用SHA1演算法計算得來。
$ git log
commit 073eaa43a0a0251b4cf6a25f8e66464268401209 (HEAD -> master)
通常會用40個16進位字元組成。
具備1對1函數特性。
也就是 1個 input value 對應 1個 output value.
由於兩個不同的檔案,透過SHA1演算法計算,會有不同的值。
因此,SHA1演算法可以拿來應用。達到類似指紋的目的。
有沒有可能,兩個不同內容的檔案,有同樣的SHA1值。這個機率非常低。這個狀況稱為碰撞。
Example:
Google暴力修改PDF檔9兆次,讓修改後的PDF檔與原始檔具有相同的SHA1值。
REF:
- Google Security Blog: Announcing the first SHA1 collision
- 史上第一例!Google破解SHA1實現碰撞攻擊
但git計算SHA1值時,還有加料。
在git中,每個物件都有他的SHA1值。
commit時,發生什麼事?
git中有4種物件
- blob。跟檔案有關。
- tree。跟資料夾及檔名有關。
- commit。存放commit資訊。
- tag。存放tag。
REF:
https://youtu.be/LgTf7m5B0xA?t=909
在repository中,新增一個檔案時。此時該當案處於untracked的狀態。
當使用command git add把該檔案加入後,就會產生一個blob物件。
當使用command git commit,git就會產生tree、commit物件。
可以用command git count-objects來算物件數量。
關於reset
reset有3種參數
- --mixed。當沒有下任何參數時,預設使用- --mixed參數。
- --soft。
- --hard。
REF:
https://youtu.be/LgTf7m5B0xA?t=1239
關於 branch (分支)
有人可能會認為branch就是把檔案全部copy出來,改完後,再合併回去。但這樣成本就很高。
在
git裡面開branch很便宜。
branch只是一個指向某個commit的指標。
所謂的branch,就是一個有40個字元的檔案。(SHA1值) (不用copy一堆檔案,所以很便宜)
在.git/refs/heads/master的檔案中,會記錄 master branch。
使用command git branch,可以看到目前的repository中有哪些branch。
使用command git branch [branch name],可以在目前的repository中新增branch。
branch的檔案會存在.git/refs/heads/資料夾下。每個檔案,表示一個branch。
如果刪除某個檔案,就是刪除某個branch。
如果更改某個檔名,就是更改branch的名字。
REF: https://youtu.be/LgTf7m5B0xA?t=1269
關於 HEAD
HEAD就是指向某個branch的指標。存放在檔案.git/HEAD中。
使用command git checkout [branch name]可以改變.git/HEAD值。
請勿手動改.git/HEAD值,不會報錯,但git會出錯。
REF:
https://youtu.be/LgTf7m5B0xA?t=1393
A merge B vs. B merge A
rebase vs. merge
REF:
https://youtu.be/LgTf7m5B0xA?t=1756
預設的branch一定要叫 master 嗎?
不一定。這只是一個慣例。
要不要遵守,就隨意。
REF:
https://youtu.be/LgTf7m5B0xA?t=1839
合併過的branch可不可以砍掉?
可以。
砍合併過的branch,不會影響物件的存在。
REF:
https://youtu.be/LgTf7m5B0xA?t=1851
master branch可不可以砍掉?
可以。
砍合併過的branch,不會影響物件的存在。
REF:
https://youtu.be/LgTf7m5B0xA?t=1873
可以砍任何的branch,但前提是人(HEAD)不能在那個branch上,否則要去哪裡?
另外,救branch的方法很多。所以,git要刪檔,不是那麼簡單。
關於 tag (標籤)
tag跟branch很像,但tag不會隨著commit而前進。
git做資源回收 (garbage collection)
使用command git count-objects,可以看到物件數量跟大小。
使用command git gc,強制手動觸發回收機制。
使用command git count-objects,可以看到數量變成0。
但其實不是不見,而是被打包。
使用command tree .git,可以看到藏在object/pack/的資料夾下。
REF:
https://youtu.be/LgTf7m5B0xA?t=2042
如何新增客製化的git指令?
REF:
https://youtu.be/LgTf7m5B0xA?t=2086
相關連結
git官網:
https://git-scm.com/
YouTube播放清單: Git 程式版本線上課程教學 - 由簡單到難
https://www.youtube.com/playlist?list=PL2SrkGHjnWcxw6N1-hg34nWy8UWsFOn5V
YouTube: 高見龍 - 你知道 Git 是怎麼一回事嗎
https://www.youtube.com/watch?v=LgTf7m5B0xA
YouTube播放清單: 高見龍 - GIT 小教室 https://www.youtube.com/watch?v=VShhhq_5sMc&list=PLBd8JGCAcUAF2_im__kqZTfEAKnlmfPJy
YouTube: 高見龍 - 藉由視覺化效果來學習 Git 觀念 https://www.youtube.com/watch?v=5joXSO4kSCM
Leave a comment