# git 實作練習 1 @ver 0.1.2 @date 2019-02-26 12:38:11 (星期二) @ver 0.1.1 @date 2019-02-18 08:07:05 (星期一) > 萬物皆可 git > > git 是文件版本管理系統, 它不僅僅是管理文字格式的程式碼, 包括非文字格式的二元檔案, 例如圖片 jpg, png 或文件 word, excel, ppt ... 等 binary 檔案, 都可以利用 git 搭配各種文件解析 plugin 程式, 進行文件檔案的版本追踪控制及管理. > > 每一次提交到倉庫, 相當於把現有文件做一次快照 (snapshot) , git 用各種方式把差異, 記錄在 .git 倉庫裡. 所以在某一個時刻想查看曾經某一個當下提交的程式碼時, 便可立即搭時光機還原返回那一個時間點的版本. 當然, 既然穿越到過去, 也得回到未來. 下一道指令, 就從過去那個版本, 再回到正在傷腦筋的現在這一刻. ```shell [alex@nvda /tmp/prj1 ]$ git --version git version 2.11.0 [alex@nvda /tmp/prj1 ]$ ``` 以下請大家跟著我一邊實作基本操作, 同時講解對應的各種 git 功能, 下列是此次會用到的命令 ```plaintext git config git init git status git status -s git add {filename} git add . git commit -m '記錄一下此次提交修改的相關訊息' git log ``` > **注意 : ** > > 大家可以在 /tmp 下實作, 或在自己的 /home/ooo/ 目錄下, 如果在 /tmp 之下, 記得要使用不同名稱的專案子目錄. > > 在執行結果裡, 會有 # 標記, 此標記之後代表說明 999. ## git config 設定基本識別資料 安裝 apt install git 之後 首次使用 git 要先設定基本識別資料, 這很重要, 因為每次提交會把這些基本識別資料加入倉庫, 而且提交後不能再修改, 除此之外, 設定檔裡面還有許多設定會讓你更方便使用命令列來操作 git . 基本資料設定檔預設是個人 home 目錄下的 ~/.gitconfig, 因為每個人用自己的帳號登入之後, 便以此為準. 但也可以放在專案目錄之下, 至於為何需要如此設置, 後續再研究. ### 命令 ```bash ll ~/.gitconfig ``` ### 執行結果 ```shell [alex@nvda ~ ]$ ll ~/.gitconfig ls: 無法存取 '/home/alex/.gitconfig': 沒有此一檔案或目錄 [alex@nvda ~ ]$ ``` 因為剛開始使用 git, 現在 .gitconfig 還沒產生, 所以找不到此檔案 --- 建立自己的姓名及郵件, 切記要加 --global, 設定檔才會是在 ~/.gitconfig, 否則會放在現在目錄之下 ### 命令 ```bash git config --global user.name alex # 請輸入自己的姓名, 建議用英文字母, 聽說中文會有一些問題 git config --global user.email alex@forblind.org.tw # 請輸入自己的電子郵件信箱 ``` ### 執行結果 ```shell [alex@nvda ~ ]$ git config --global user.name alex [alex@nvda ~ ]$ git config --global user.email alex@forblind.org.tw ``` 查看 config 設定 ### 命令 ```bash git config --list cat ~/.gitconfig ``` ### 執行結果 ```shell [alex@nvda ~ ]$ git config --list user.name=alex user.email=alex@forblind.org.tw [alex@nvda ~ ]$ cat ~/.gitconfig [user] name = alex email = alex@forblind.org.tw [alex@nvda ~ ]$ ``` ### 參考 : 其它有用的設定 ``` git config --global alias.co checkout git config --global alias.br branch git config --global alias.st status git config --global alias.l "log --oneline --graph" git config --global alias.ls 'log --graph --pretty=format:"%%h <%%an> %%ar %%s"' git config --global core.editor emacs ``` 我們先加上一個好用的 alias ### 命令 ```bash git config --global alias.st status git config --list ``` ### 執行結果 ```shell [alex@nvda ~ ]$ git config --global alias.st status [alex@nvda ~ ]$ git config --list user.name=alex user.email=alex@forblind.org.tw alias.st=status ``` 999. ## 建立專案 首先我們要先建立專案子目錄, 在此目錄之下的所有檔案, 都會被 git 索引追踪管理, 除非在 .gitignore 把它排除忽略 (例如 : *.bak) ### 命令 ```bash cd /tmp mkdir prj1 cd prj1 ls -a ``` #### 執行結果 ```shell [alex@nvda /tmp ]$ cd /tmp # 先進入 /tmp [alex@nvda /tmp ]$ mkdir prj1 # 專案子目錄名 [alex@nvda /tmp ]$ cd prj1 # 再進入專案子目錄 [alex@nvda /tmp/prj1 ]$ # 完成 [alex@nvda /tmp/prj1 ]$ ls -a # 檢視現有專案子目錄的檔案 . .. [alex@nvda /tmp/prj1 ]$ ``` 999. ## git init 初始本地倉庫 Repository git 初始化的目的是要讓 git 開始對這個目錄(含各層級的子目錄)下的所有文件進行版本控制, 所以每個專案只要做一次即可 ### 命令 ```bash git init ls -a ``` ### 執行結果 ```shell [alex@nvda /tmp/prj1 ]$ git init Initialized empty Git repository in /tmp/prj1/.git/ # 出現此行文字, 表示初始化完成 [alex@nvda /tmp/prj1 ]$ ls -a . .. .git # 檢查會發現多了一個 .git 的子目錄, 這個是本地倉庫的所在地 [alex@nvda /tmp/prj1 ]$ ``` 999. ## 短短的幾行程式碼 現在先寫幾個簡單的程式碼及文件檔案, 分散在幾個不同的子目錄裡 ### 命令 ```bash vi index.php vi README.md ls -a ``` index.php 程式碼如下 : ```php ``` ### 命令 ```bash vi README.md ``` README.md 說明檔如下 : ```plaintext 這是我們的第一個版本的說明檔 現在時間是 2019-02-19 15:14:43 (星期二) ``` ### 執行結果 ```shell [alex@nvda /tmp/prj1 ]$ ls -a . .. .git index.php README.md # 剛剛新建的兩個檔案 index.php README.md [alex@nvda /tmp/prj1 ]$ ``` 999. ## git status 觀察檔案的變化 第二個接觸到的 git 命令是 git status, 列出此專案檔案變化的相關資訊 ### 命令 ```bash git status ``` ### 執行結果 ```shell [alex@nvda /tmp/prj1 ]$ git status On branch master Initial commit Untracked files: (use "git add ..." to include in what will be committed) README.md index.php nothing added to commit but untracked files present (use "git add" to track) [alex@nvda /tmp/prj1 ]$ ``` 關於檔案狀態 注意看 Untracked files: 這一行之下的幾個檔名, 都是剛新增的檔案. Untracked 的 意思是『尚未被 git 索引追踪』. git status 執行結果, 可能還會有另兩種提示 如果是 Changes not staged for commit: 表示這個檔案『先前已被 git 索引追踪, 但修改內容後, 沒有用 git add 告知我們要在這次的提交中更新其狀態』. 如果是 Changes to be committed: 表示這些檔案『已被 git 索引追踪, 而且已使用 git add 告知狀態更改』, 也就是進入暫存區(索引). 檔名前面還會再加上三種不同的指示 * deleted: 表示此檔案被刪除 * modified: 表示檔案內容有更動 * new file: 表示為此次提交要新增追踪的檔案 檔案狀態的三種不同提示 : * {#MY-LIST-ID .my-list-type-disc start=1 type=A} Untracked files: ```plaintext 從上次提交後, 在工作目錄下新建立的檔案, 尚未被 git 索引追踪 ``` * Changes not staged for commit: ```plaintext 檔案在先前已被 git 索引追踪, 但修改內容後, 沒有用 git add 告知要在這次的提交中更新其狀態 ``` * Changes to be committed: ```plaintext 檔案在先前已被 git 索引追踪, 而且已使用 git add 告知狀態更改 ``` 後面兩種 Changes 開頭的提示, 在每一個檔案名稱前, 可能有下列三種標示 : 1. deleted: 表示此檔案被刪除 2. modified: 檔案內容有修改過 3. new file: 新加入索引追踪的檔案 999. ## 觀察檔案的變化之短格式 現在在命令末尾加上 -s , 它的意思是 Short Format 短格式 因為先前有指定 alias, `git config --global alias.st status` 所以 `git st -s` 等同 `git status -s` 命令, 以後會全部使用 git st 來操作 ### 命令 ```bash git status -s git st -s ``` ### 執行結果 ```shell [alex@nvda /tmp/prj1 ]$ git status -s # Short Format 短格式 ?? README.md ?? index.php [alex@nvda /tmp/prj1 ]$ git st -s # alias 用法的 Short Format 短格式 ?? README.md ?? index.php [alex@nvda /tmp/prj1 ]$ ``` 跟先前顯示出來的方式有點不同, 也簡短了許多, 最前面兩碼 ?? 雙字母狀態碼, 表示 Untracked 未被索引追踪 雙字母狀態碼可能會有下列七種字元 * ' ' = 未修改 (空白) * M = 修改 * A = 已添加 * D = 刪除 * R = 重命名 * C = 複製 * U = 更新但未被合併 > X shows the status of the index. 暫存區(索引)的狀態 > > Y shows the status of the work tree. 工作目錄的狀態 > > 以下的 "被索引追踪", 也就是說曾經 git add 過此檔案, 在那個當下的文件會放入暫存區(索引) | X 第一碼
暫存區(索引)的狀態 | Y 第二碼
工作目錄的狀態 | 中文說明 | 英文說明 | | :------ | :------ | :-- | :-- | | ? | ? | 未被索引追踪 | untracked | | ! | ! | 忽略此檔案(要搭配參數 --ignored, 才會顯示) | ignored | | ------- | ------- | ----------------- | -------------------------- | | A | ' ' | 新檔案, 被索引追踪, 尚未提交 | added to index | | A | M | 新檔案, 被索引追踪, 尚未提交, 但工作目錄下的檔案內容有修改異動 | added to index, modified | | A | D | 新檔案, 被索引追踪, 尚未提交, 但工作目錄下的檔案已改檔名或被刪除 | added to index, deleted or renamed | | ' ' | M | 已被索引追踪, 尚未更新到暫存區(索引), 但工作目錄下的檔案有修改異動 | not updated, modified | | ' ' | D | 已被索引追踪, 尚未更新到暫存區(索引), 但工作目錄下的檔案已改檔名或被刪除 | not updated, deleted | | M | ' ' | 工作目錄下的檔案有修改異動, 被加入索引追踪, 尚未提交 | TBD | | M | M | TBD | TBD | | M | D | TBD | TBD | | D | ' ' | TBD | TBD | | D | M | TBD | TBD | | R | ' ' | 在暫存區(索引)中重新命名, 被索引追踪, 尚未提交 | renamed in index, modified | | R | M | 在暫存區(索引)中重新命名, 且工作目錄下的檔案有修改異動 | renamed in index, modified | | R | D | TBD | TBD | | C | ' ' | TBD | TBD | | C | M | TBD | TBD | | C | D | TBD | TBD | | ------- | ------- | ----------------- | -------------------------- | | ' ' | [MD] | 已被索引追踪, 但未更新到暫存區(索引) | not updated | | M | [ MD] | git add 之後, 更新到暫存區(索引) | updated in index | | A | [ MD] | 已添加到暫存區(索引) | added to index | | D | [ M] | 從暫存區(索引)中刪除 | deleted from index | | R | [ MD] | 在暫存區(索引)中重新命名 | renamed in index | | C | [ MD] | 複製到暫存區(索引)中 | copied in index | | [MARC] | ' ' | 暫存區(索引)和工作目錄匹配 | index and work tree matches | | [ MARC] | M | 工作目錄自暫存區(索引)以來發生了變化 | work tree changed since index | | [ MARC] | D | 在工作目錄中被刪除 | deleted in work tree | | ------- | ------- | ----------------- | -------------------------- | | D | D | 未被合併, 全都被刪除 | unmerged, both deleted | | A | U | 未被合併, 由我們添加 | unmerged, added by us | | U | D | 未被合併, 被他們刪除 | unmerged, deleted by them | | U | A | 未被合併, 由他們添加 | unmerged, added by them | | D | U | 未被合併, 被我們刪除 | unmerged, deleted by us | | A | A | 未被合併, 全都被添加 | unmerged, both added | | U | U | 未被合併, 全都已修改 | unmerged, both modified | 999. ## 把檔案交給 git 管理 (use "git add" to track) 這是上一節 git status 命令的最後一句話. ### 命令 ```bash git add ``` ### 執行結果 ```shell [alex@nvda /tmp/prj1 ]$ git add Nothing specified, nothing added. Maybe you wanted to say 'git add .'? [alex@nvda /tmp/prj1 ]$ 原文照翻 : 沒有指定任何東東, 所以沒有加入索引追踪. 也許你要下的命令是 `git add .` ``` 照它指示下命令, git add 就是把新的未索引追踪檔案加入到暫存區 ### 命令 ```bash git add . ``` ### 執行結果 ```shell [alex@nvda /tmp/prj1 ]$ git add . ``` >> **注意 :** >> `git add .` 沒有任何回應, 這表示, 一切正常 再度觀察檔案的變化 ### 命令 ```bash git status git status -s ``` ### 執行結果 ```shell [alex@nvda /tmp/prj1 ]$ git status On branch master Initial commit Changes to be committed: (use "git rm --cached ..." to unstage) new file: README.md new file: index.php [alex@nvda /tmp/prj1 ]$ git status -s A README.md A index.php [alex@nvda /tmp/prj1 ]$ ``` new file: 或最前面兩碼 "A ", 表示此檔案已添加到暫存區(索引), 加入 git 索引追踪為新檔案 999. ## git commit 最後一哩路 commit 提交到 repo, 才算完成整個 git 版本管理流程 ### 命令 ```bash git commit -m '第一次提交到 git repo' ``` ### 執行結果 ```shell [alex@nvda /tmp/prj1 ]$ git commit -m '第一次提交到 git repo' [master (root-commit) f2ed5d7] 第一次提交到 git repo 2 files changed, 6 insertions(+) create mode 100644 README.md create mode 100644 index.php [alex@nvda /tmp/prj1 ]$ ``` 看到這些訊息, 代表完成此階段的提交 再度觀察檔案的變化 ### 命令 ```bash git status git status -s git st git st -s ``` ### 執行結果 ```shell [alex@nvda /tmp/prj1 ]$ git status On branch master nothing to commit, working tree clean [alex@nvda /tmp/prj1 ]$ git status -s [alex@nvda /tmp/prj1 ]$ git st On branch master nothing to commit, working tree clean [alex@nvda /tmp/prj1 ]$ git st -s [alex@nvda /tmp/prj1 ]$ ``` 沒東東...所以...OK啦 999. ## git log 看看提交後的訊息 ### 命令 ```bash git log git log --stat git log --pretty=format:"%h - %an, %ar : %s" ``` ### 執行結果 ```shell [alex@nvda /tmp/prj1 ]$ git log 1 commit f2ed5d757c9a81de0d1ccd601af1e4a6a48333e4 2 Author: alex 3 Date: Tue Feb 19 16:24:19 2019 +0800 4 5 第一次提交到 git repo (END) 要按 Q 鍵離開此檢視畫面 [alex@nvda /tmp/prj1 ]$ git log --stat 1 commit f2ed5d757c9a81de0d1ccd601af1e4a6a48333e4 2 Author: alex 3 Date: Tue Feb 19 16:24:19 2019 +0800 4 5 第一次提交到 git repo 6 7 README.md | 2 ++ 8 index.php | 4 ++++ 9 2 files changed, 6 insertions(+) [alex@nvda /tmp/prj1 ]$ git log --pretty=format:"%h - %an, %ar : %s" 1 f2ed5d7 - alex, 14 minutes ago : 第一次提交到 git repo (END) [alex@nvda /tmp/prj1 ]$ git log --oneline 1 f2ed5d7 第一次提交到 git repo [alex@nvda /tmp/prj1 ]$ ``` 等後面有很多次提交, 再來討論 git log 的應用 999. ## 本章總結 ### 本章使用 git 命令總結 ```bash git config # 設定基本識別資料 git init # 初始化, 在這個專案之下, 建立 .git 這個子目錄及裡面的相關結構, 所以每個專案只要做一次即可 git status # 觀察檔案的變化 git status -s # 觀察檔案的變化之短格式 git st # git alias 觀察檔案的變化 git st -s # git alias 觀察檔案的變化之短格式 git add # 將此路徑檔案加入暫存區(索引) git add . # 將所有檔案加入暫存區(索引) git commit -m 'message' # 暫存區(索引)提交至倉庫, 包含提交訊息 git log # 顯示提交的結果及訊息 git log --stat # 顯示提交的結果及訊息 git log --pretty=format:"%h - %an, %ar : %s" # 顯示提交的結果及訊息 ```