[ 學習筆記系列 ] 很基礎的 Command Line 與 Git


Posted by ClayGao on 2020-03-19

前言

從今天開始,我的部落格開張了,原本在 Medium 的部分文章也會轉移過來。

目前剛工作兩個禮拜,心想也該是時候把一些之前寫的筆記搬運過來,一方面重新整理,一方面也想分享給更多的人。

但由於大概是約一年前的東西了,許多資訊可能需要更新,所以原文應該也會有一些修改,如果文章部分有錯誤,還希望讀者不吝指教。


Command Line

關於 Mac 必備 iterm2,可以參考這一篇文章做前置,

我是一直到踏入職場才知道 Command Line 可以用到這麼出神入化,因為工作場所多為 Ruby 工程師,所以操作起來也相當出神入化,這邊介紹幾招小的。

善用你的快捷鍵

以 Mac 來說,最常使用的應該是 command + T,直接開一個新的分頁

或者是 command + U,直接垂直分割新頁面

又或者是 command + shift + U,水平分割新頁面

連續使用上述指令就會有以下效果:

  • command + T

  • command + U

  • command + shift + U

延續上一個位置

這個選項設置對要連續在同個專案跑 Terminal 應該有用得多,它的作用是當我們開新的視窗時,會延續上一個視窗所在的路徑位置

按下 command + ,,打開 Setting,選擇「 Profiles 」標籤,紅框處打勾

如此打開新的視窗,就會延續原本的位置了!

普通會使用到的指令

以下的指令可能會根據你的作業系統有所不同,但多是大同小異。

另外如果是 Windows 使用者,建議下載 Cmder 來取代內建的小黑窗,這裡的取代是指使用上取代,Cmder 不會蓋掉內建的小黑窗。

指令名稱 指令內容
ls / ls -al 列出該清單 / 列出該清單副檔名
cd / cd .. 切換至該目錄 / 回到上一層目錄
mkdir 創建資料夾
rm / rm -rf 刪除檔案 / 強制刪除該目錄
rmdir 刪除空的目錄
">" 導向,可用於輸入或輸出
touch 創建檔案或更名
cp A B 複製 A 檔案為 B 檔案
grep a B 在 B 檔案裡面揪出內中為 a 的字
wget 後面接網址,下載之
pipe 將 pipe 前面的輸出變成 pipe 後面的輸入,可以將 pipe 視為 "接著做..." ( 該指令在 md 表格無法正常顯示 )
man 列出該指令使用手冊
pwd 印出你現在的位置
telnet <IP Adress:Port> 看 Port 是否有開啟,若有,可以輸入並發送資料
curl 發一個 GET 的 request 到該 URL 並返回 response
nslookup 後面不接域名,可以查到本機 DNS 基礎訊息,其功能相當強大

上述指令也不是說每個都很常用,但大概知道他是什麼意思即可

另外附上個人補充指令 ( Windows / Linux 指令 / Mac OS 不確定 )

指令名稱 指令內容
start 開啟該檔案 ( 用預設程式 ) ( cmder 適用 )
tree 這很酷,可以列出該目錄內部與內中子目錄的樹狀圖分布
tasklist 看現在正在運行的程式
ipconfog 看電腦的網路相關資訊
cls 如果你嫌 clear 太冗長...

其實 Command Line 的指令還有很多,但由於工作幾乎都會用到,所以其實不用特地去背,常用就熟了,包括用快捷鍵開新視窗也是。

另外補充一下,有些指令是需要安裝才能使用的,比如說我想要快速用 VScode 打開一個檔案或資料夾,可以使用 code 指令,空一格接你要的檔名或資料夾,那可能就必須要從 VScode 安裝這個指令,可以參考 2018 IT 鐵人賽的一篇 VScode 配置好文


基礎 Git

以下的兩篇文章都是從過往的筆記與作業整理出來的,適合完全不懂 Git 的初學者,當然這邊也很建議去閱讀高見龍大神的 Git 介紹文。

教你朋友學 Git

請確定你這邊已經安裝好 Cmder 或已經開啟你 MAC 的 iterm2,之後開啟我剛剛給你的 Cmd 指令教學,用 mkdir 指令創建一個資料夾 test1,然後輸入下列指令開始 git 版控

git init

對了,輸入 ls -al 應該可以看到 .git 資料夾,git init 指令創造了這個資料夾。同理,要移除 Git。原理就是刪除資料夾即可,因此指令 rm -rf .git 可以將 Git 移除。


開始操作

首先你必須建立一個概念,git 有分為工作區、暫存區與倉庫,檔案進入版控的程序也是如此,大概是如下表格

區域名稱 代表意思 如何進入下一區
工作區 尚未 add 加入暫存區 git add 檔名
暫存區 檔案 add 後暫存的地方 git commit -m "commit訊息"
倉庫 檔案完成版本控管儲存之地 這樣已經完成了這一版本

在你剛剛輸入 git init 的時候,你就已經替這個資料夾建立了一個 repository,簡稱 repo,代表這個資料夾已經有了版控。你可以輸入 git status 來看目前的版控狀態

git status  顯示版控狀態

應該會顯示 Nothing to commit,因為沒有任何檔案。

這時候輸入 touch test.js 創建這個檔案,然後我們就可以開始。


再一次輸入 git status,你應該會看到以下資訊

On branch master //目前在 master 這個 branch

No commits yet //還沒有 commit 檔案

Untracked files:
(use "git add <file>..." to include in what will be committed)

   test.js

nothing added to commit but untracked  files present (use "git add" to track)

可以看到 test 被歸類在 Untracked files 底下,也很貼心地告訴你可以使用 git add 加入版控,也是將檔案放入暫存區。


這時候請輸入 git add test.js,將其加入版本控管之中

git add <filename> // 將檔案加入暫存區

或者你之後編輯有多個檔案,也可以輸入下列指令,一次加入所有檔案

git add . // 將工作區所有檔案加入暫存區

承上,一次將工作區所有檔案加入暫存區的確方便,但有幾個檔案我並沒有想讓它加入暫存區,更正確地說其實它根本不需要版本控管,怎麼辦呢?

你可以創建一個檔案名為 .gitigonre,顧名思義就是不會被 Git 所理會的檔案集合,創建它並編輯,輸入你不想加入 Git 的檔案名稱

.gitignore // 內含不需要 Git 版控的檔案名稱

所以,將檔案加入暫存區之後,輸入 git status,就可以看到 test.js 已經加入版本控制。

這時候打開 test.js 並輸入幾行字再儲存關閉,輸入 git status 會顯示 test.js 是 modified 的狀態。代表 Git 偵測到這檔案內容有變動,又送它去到了工作區了。

這時候輸入 git diff,會輸出的是你現在這份工作區的檔案和原本暫存區的檔案的差異。

比如說你剛剛打的幾行字是 123,那 git diff 輸出的結果就是+123,輸出內容中,行首是 + 代表增加,- 代表刪減。

`git diff` // 顯示現在工作區的檔案與上一版 / 暫存區的檔案的差異

關於 git diff 還有很多討論,其實它還有多種不同用法,不同的指令比較的區域也不同

比如下列這個是比較兩個 commit 之間的不同之處:

git diff commit1 commit2

現在你都已經完成了你想要在 test.js 中的內容,那麼就讓我們正式把它放入倉庫吧!

使用 git commit -m "messenge" 可以讓你將所有暫存區的檔案全部放入倉庫。messenge 是你此次 commit 的說明。

git commit -m "messenge"

若是你常常將檔案編修,甚至會為每次的小變動都來個 commit,重複輸入 git add 與 commit 指令會很麻煩,所以我們可以合二為一:

git commit -am "messenge"

但記住這個指令對 Untracked File 底下的檔案無用,你至少需要第一次的 git add 將其加入 Git 控管。


使用了一陣子,也 commit 了兩三次,我要怎麼看 commit 紀錄呢?輸入 git log 吧,它就像是進貨單一樣!

git log  // 顯示 commit 紀錄

從上到下分別為

  • commit id // 該 commit 的身分證
  • Author // 執行者
  • Date
  • 該 commit 的 messenge

習慣上面的格式之後,git log 後面可以加上 --oneline 這個參數,如此顯示會更簡潔,commit id 也只會顯示前七碼,很常拿來使用也易記住或辨識。

git log --oneline // 顯示簡潔 commit 紀錄

當你審視 git log 的時候,突然覺得現在這個 commit 似乎沒有上個版本還要好,我能夠時光倒流,回到上個版本嗎?

答案是可以的,輸入 git checkout commitID 即可( 全碼或前七碼都可以 )

git checkout commitID

要切回到現在版本則是輸入:

git checkout master

branch 概念

雖然可以 checkout 回到過去的版本,但這樣編輯起來還是有點怕檔案控管出錯出包,能有什麼方法?

所以一個良好的習慣是,我們在編輯一個既有的專案時都應該先替其創一個 branch 來做編輯動作。除了安全起見外,多人同時編輯一個大專案時,也能達到因為各自有各自的 branch ,而互不影響開發的情況。

所以,如果你還是覺得這個概念很模糊,不如可以先暫時把它想成 Netflix 的使用者,一個 Netflix 帳號能夠多人共用,你和你女朋友的觀影可能不同,比如說你愛看李屍朝鮮安眠書店,所以你的使用者紀錄有這兩部,她愛看性愛自修室黑鏡,所以她的使用者紀錄也有這兩部。

你的紀錄 女友紀錄
李屍朝鮮 性愛自修室
安眠書店 黑鏡

有一天,你和你的女友都很想看最近出的新劇:愛死機器人,妳女友叫你等她下班一起看,好死不死她最近每天加班,而你因為在胡老師的課程中表現良好,進度超前,空餘時間比較多,所以想偷看。

可是你怕用自己的使用者看,她若偷看你紀錄會發現。
如果用她的使用者看更不行,她會直接知道。

所以聰明的你,當然是先創一個新的使用者,偷看完再把它刪掉囉!

你的紀錄 女友紀錄 新使用者紀錄
李屍朝鮮 性愛自修室 愛死機器人
安眠書店 黑鏡

所以大概可以把 branch 想成這樣的概念,而 commit 就是該 branch 底下的使用者紀錄。


創建 branch 並切換至該 branch

你可以透過 git branch week1 來創建一個叫做 week1 的新 branch

git branch <name>

再使用 git checkout week1 跳到該 branch,有發現這跟之前切換 commit 版本再切回來很像嗎? 沒錯,當 checkout 至該 branch,預設會停留在最新的 commit。
所以之前的 git checkout master,其實是指切換到該 branch 的意思。而 master 是 Git 預設的 branch,就像新辦 Netflix 預設的使用者一樣。

git checkout <branch name>

如果疑惑自己目前在哪個 branch,可以輸入 git branch -v,會顯示 branch 列表,前面有 * 號則表現你目前所在的 branch

git branch -v

合併 branch 與刪除 branch

時過境遷,你的女友跟別人跑了,而你當初用來看愛死機器人那個使用者,也早因為懶得切換看了不少影集,卻大多都只看一半。

有一天你想說能不能把你原本的使用者和之後這個新創的使用者合在一起,這樣就不用那麼累,要看安眠書店就要切回原本的使用者,要看愛死機器人又要切到新的使用者,若把兩個使用者合併在一起,不就太棒了?( 反正女友也跑了 )

Git 也有這個功能,切換到你想以其為主的那個 branch,我以 master 為主,想把 week1 這個分支拉過來和我這個主要的 branch 合而為一

即 master <- week1

做法則是 git checkout master,先至這個 branch

接著輸入這個指令 git merge week1

git merge <branchName>

如此就完成了。

雖然兩者已經合二為一,但 week1 還在,並沒有消失。你可以輸入 git branch -d week1 將它刪除。

git branch -d <branchName>

衝突(conflict)

有一天你想到,你 Netflix 原本的紀錄和你之前新開的紀錄都有用來看 JOJO 的奇妙冒險,那合併之後的集數紀錄會以哪個為主呢?

在 Git 之中,如果 branch A merge branch B,而兩個檔案較之於最初的狀況而言都有做修改,那麼 merge 的時候 Git 會告訴你是哪個文件有這樣的衝突,並且你可以進入該文件自由選擇你想保留或刪除哪一個部分(兩者文件內容全留下當然也可以)

假設這個都有做修改的文件叫做 jojo.js,那麼 merge 時發現衝突時會顯示:

Auto-merging jojo.js
CONFLICT (content): Merge conflict in jojo.js
Automatic merge failed; fix conflicts and then commit the result.

意思是當 Git 要自動幫你 merge 時,發現 jojo.js 這個檔案有衝突問題,需要你修正

輸入 git status 也可以看到輸出 Unmerged paths: 底下有 both modified: jojo.js

進入 jojo.js 檔案,相異之處會特別標示

以剛剛 Week1 合併至 master 為例

============ 用來分開兩個 branch 各自不同的部分

jojo.js
<<<<<<<<<<<<<<<< HEAD
master 內容
====================
week1 內容
>>>>>>>>>>>>>>>> week1
其他相同的部分

至此,是一個自由編輯的模式,所以你要留那一個 branch 的部分都是可以的。


Git 整理- Git 指令相關

最後我們再重新整理上述提到的部分

指令名稱 指令內容
git init 安裝 Git,會產出一個叫做 .git 的資料夾
git add / git add . 將檔案加入暫存區 / 將所有檔案加入暫存區 ( 切記新增的檔案必使用! )
git commit -m " " / git commit -am " " 將檔案加入倉庫區 / 將檔案加入暫存並加入倉庫區," " 內中請輸入訊息
.ignoregit 這不是指令而是文件名稱,把不要被 git 管控的檔案加入其中
git status 看目前 Git 管控中的檔案狀態
git log 看所有的 Commit 紀錄,後面加入 --oneline 可以看簡化版本的紀錄
git diff 比較檔案修改前後的不同,後面接兩組 commitID 可以看到兩組之間的差別
git branch 看目前的 branch 分支,與後面加參數 -v 相同,後面接名稱可以建立該名稱的 branch
git branch -d / git branch -D 刪除該 branch,-D 可以強制刪除未 merge 過的 branch
git checkout 切換到該 branch
git merge 將該 branch 拉回融合至現下的 branch

衝突

merge 若衝突,分辨方法:

以 week1 這個 branch 被 merge 至 master 中,123.js 這個檔案產生衝突,打開檔案會顯示:

123.js 檔案內容
<<<<<<<<<<<< HEAD
master 內容
================
week1 內容
>>>>>>>>>>>> week1
其它相同的部分

簡而言之,============ 用來分開兩個 branch 中該檔案各自不同的部分,而至此,是一個自由編輯的模式,所以你要留那一個 branch 的部分或者你要怎樣重新編輯都是可以的。

GitHub 指令相關

指令名稱 指令內容
git remote 使用 git remote origin master 連線到該 repo
git remote -v 看當下連接的 GitHub
git pull 將 Github 的 repo 拉下來 ( 下載 ),預設通常為 git pull origin master
git push 上傳,後面接該 branch 的名稱

其它補充

指令名稱 指令內容
git reset HEAD 取消被 add 至暫存區的檔案
git commit --amend 取消上一個 commit

結語

上述大概就是非常基礎的 Git 相關指令,這邊也需要提一下,Git 是版本控制軟體,而 GitHub 則是一項服務,兩者並不相同。

另外實際工作上,還會遇到其他的狀況,是上述指令沒有介紹到的。

比如說我自己的版控習慣,導致做了一些小功能就多了好幾個 commit,但這樣 Push 上去主管看到這麼多 commit 肯定會搖頭,所以 Git 也提供了 Squash 這個指令,讓我們可以把多個 commit 匯合成同一個 commit,也可以替這個 commit 重新命名,交出漂亮的 PR。

但這邊就不贅述了,網路上已有有很棒的文章,可以參考以下兩篇:

大概就這樣了,後續會繼續補上先前的心得筆記文。


#Git #command line #新手 #初心者







Related Posts

解構賦值 Destructuring Assignment

解構賦值 Destructuring Assignment

自駕車 Software Stack 架構介紹

自駕車 Software Stack 架構介紹

如何成為專家 - 技巧篇(尚未完成,先放出來供需要的朋友參考)

如何成為專家 - 技巧篇(尚未完成,先放出來供需要的朋友參考)


Comments