# Git
[TOC]
{%hackmd @88u1wNUtQpyVz9FsQYeBRg/r1vSYkogS %}
###### tags: `Git`
> 以`\190614師兄打卡系統\code\`此專案目錄為例,展示`git`。
這是一個桌面應用的開發,但以下不討論專案內容
# 安裝與環境
很簡單直接跳過吧
# 終端機及常用指令介紹
|--Windows--|--MacOS / Linux--|--說明--|
--------------|:-----:|-----:| ----:|------------------------
cd | cd | 切換目錄
cd| pwd| 取得目前所在的位置
dir| ls| 列出目前的檔案列表
mkdir| mkdir| 建立新的目錄
無| touch| 建立檔案
copy| cp| 複製檔案
move| mv| 移動檔案
del| rm| 刪除檔案
cls| clear| 清除畫面上的內容
:::warning
由於我是用`Git Bash`所以要參照linux指令
:::
## 查看Git版本
```
// 其中 $ 為提示字元,在輸入指令時不用輸入該符號,否則會錯誤,若是使用 windows cmder 預設是 λ
$ git --version
git version 2.23.0.windows.1
```
## 路徑切換及查看
```git=
// cd到E的專案位置
s710262101@ios7188-826 MINGW64 ~
$ cd E:/我的雲端硬碟/drive/190614師兄打卡系統/code
```
```git=
// 確認當前路徑
s710262101@ios7188-826 MINGW64 /e/我的雲端硬碟/drive/190614師兄打卡系統/code
$ pwd
/e/我的雲端硬碟/drive/190614師兄打卡系統/code
```
其他路徑相關指令
```git=
# 切換到 /tmp 目錄(絕對路徑)
$ cd /tmp
# 切換到 my_project 目錄(相對路徑)
$ cd my_project
# 往上一層目錄移動
$ cd ..
# 切換到使用者的 home 目錄中的 project 裡的 namecards 目錄
# 這個 "~" 符號表示 home 目錄
$ cd ~/project/namecards/
# 顯示目前所在目錄
$ pwd
```
## 檔案列表
> 使用 Git 前必知終端機指令:**檔案列表**
`ls` 指令可列出在目前目錄所有的檔案及目錄,後面接的 `-al` 參數,`a` 是指連小數點開頭的檔案(例如.gitignore)也會顯示,`l` 則是完整檔案的權限、擁有者以及建立、修改時間:
```git=
s710262101@ios7188-826 MINGW64 /e/我的雲端硬碟/drive/190614師兄打卡系統/code
$ ls -al
total 29
drwxr-xr-x 0 s710262101 1049089 0 十月 24 10:39 ./
drwxr-xr-x 0 s710262101 1049089 0 十月 24 10:40 ../
drwxr-xr-x 0 s710262101 1049089 0 十月 22 14:17 __pycache__/
drwxr-xr-x 0 s710262101 1049089 0 十月 22 11:02 build/
-rw-r--r-- 0 s710262101 1049089 2163 十月 24 10:39 data_tosql.py
-rw-r--r-- 0 s710262101 1049089 1318 十月 22 11:45 database_connection.py
-rw-r--r-- 0 s710262101 1049089 246 十月 22 07:29 desktop.ini
drwxr-xr-x 0 s710262101 1049089 0 十月 22 14:19 dist/
-rw-r--r-- 0 s710262101 1049089 2304 十月 17 13:58 punchSystem-7c27e17aa7de.json
-rw-r--r-- 0 s710262101 1049089 987 十月 22 11:02 pyqt5.spec
-rw-r--r-- 0 s710262101 1049089 9933 十月 24 10:39 pyqt5_main.py
-rw-r--r-- 0 s710262101 1049089 875 十月 22 14:17 pyqt5_main.spec
-rw-r--r-- 0 s710262101 1049089 7410 十月 22 11:53 sqlite_op.py
-rw-r--r-- 0 s710262101 1049089 0 十月 21 19:31 test.db
```
## 建立檔案、目錄
> 建立檔案 `touch`
```git=
s710262101@ios7188-826 MINGW64 /e/我的雲端硬碟/drive/190614師兄打卡系統/code
$ touch test.html
```
:warning: 如果 `test.html` 這個檔案本來不存在,`touch` 指令會建立一個名為 `test.html` 的空白檔案;如果本來就已經存在,則只會改變這個檔案的*最後修改時間*,不會變更原本這個檔案的內容。
> 建立資料夾 `mkdir`
```git=
s710262101@ios7188-826 MINGW64 /e/我的雲端硬碟/drive/190614師兄打卡系統/code
$ mkdir justfortest
```

:::info
以下省略
指令中的路徑::s710262101@ios7188-826 MINGW64 /e/我的雲端硬碟/drive/190614師兄打卡系統/code
:::
## 檔案操作
> `cp`複製檔案
> `mv`更改檔案名稱
> `rm`刪除檔案
```git=
$ cp test.html copy_test.html
$ mv test.html new_test.html
$ rm new_test.html
```

> 刪除在這個目錄裡所有的 html 檔:
>
```git=
$ rm *.html
```
# 使用者設定
## 帳號及信箱設定
設定使用者的 Email 信箱以及使用者名稱。
```git=
$ git config --global user.name "Lee TsungTang"
$ git config --global user.email "s710262101@gm.ntpu.edu.tw"
```
> 檢視目前設定
```git=
$ git config --list
core.symlinks=false
core.autocrlf=true
core.fscache=true
color.diff=auto
color.status=auto
color.branch=auto
color.interactive=true
help.format=html
rebase.autosquash=true
http.sslbackend=openssl
http.sslcainfo=C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt
credential.helper=manager
diff.astextplain.textconv=astextplain
filter.lfs.clean=git-lfs clean -- %f
filter.lfs.smudge=git-lfs smudge --skip -- %f
filter.lfs.process=git-lfs filter-process --skip
filter.lfs.required=true
core.editor="D:\programfile\Microsoft VS Code\Code.exe" --wait
user.name=Lee TsungTang
user.email=s710262101@gm.ntpu.edu.tw
```
:waning_crescent_moon: 如果你有安裝過 Git 相關的圖形化介面工具,可能 git `config --list` 這個指令還會輸出其它額外的設定,但至少我們剛剛的這兩行設定會新增 `user.name` 跟 `user.email` 這兩個設定。
## 設定檔的位置
所有 Git 相關的設定,預設會在自己帳號下的 `.gitconfig` 這個檔案裡,所以使用一般的文字編輯器,直接手動修改這個檔案也會有一樣的效果:
檔案:`~/.gitconfig`


## 不同專案設定不同作者
前面設定時有 `--global` 的參數,意思是要做==全域(Global)的設定==。但偶爾會遇到一些特別的狀況,例如是要幫特定的專案設定不同的作者,可以在該專案目錄下進行 Git 設定的時候,加上 ==--local 參數==:
例如
```git=
$ git config --local user.name Sherly
$ git config --local user.email sherly@5xruby.tw
```
:8ball: 如此在此專案操作時就會使用該使用者與Email操作。離開此專案後的git操作,則還是沿用Global的設定
# 新增、初始 Repository
## 初始化git目錄
由於前面已經切換到專案目錄了,此處可以直接初始化該目錄
```git=
$ git init
Initialized empty Git repository in E:/我的雲端硬碟/drive/190614師兄打卡系統/code/.git/
```
:waning_gibbous_moon: 初始化的目的是要讓 Git 開始對這個目錄進行版本控制。
其中,第 3 步這個指令會在這個目錄裡建立一個 `.git` 目錄,整個 Git 的精華就都是在這個目錄裡了。之後會詳細討論

### vscode 初始化git


## 如果目錄不想再被git控制..
請直接移除`.git`目錄,Git即失去控制權
:warning: 整個專案目錄裡,什麼檔案或目錄刪了都救得回來,但 `.git` 目錄只要刪了就沒救了。
# 提交檔案給 Git 控管
## 提交檔案
> 先以`git status` 這個指令來查詢現在這個目錄的「狀態」:
>
```git=
$ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
__pycache__/
build/
data_tosql.py
database_connection.py
desktop.ini
dist/
punchSystem-7c27e17aa7de.json
pyqt5.spec
pyqt5_main.py
pyqt5_main.spec
sqlite_op.py
test.db
nothing added to commit but untracked files present (use "git add" to track)
```
:waning_gibbous_moon: 目前所有檔案的狀態皆為`Untracked files`,意思是檔案尚未被加到 Git 版控系統裡,還沒開始正式被 Git「追蹤」
:waning_crescent_moon: `git status -s` 可以簡化輸出結果
> 先用指令建立一個內容為"hello, git"的`welcome.html`
```git=
$ echo "hello, git" > welcom.html
```

## `git add` 提交
> 把`welcome.html`這個檔案交給 Git,讓 Git 開始「追蹤」它,使用的指令是 `git add` 後面加上`檔案名稱`:
>
```git=
$ git add 'welcom.html'
warning: LF will be replaced by CRLF in welcom.html.
The file will have its original line endings in your working directory
```
:waning_crescent_moon: 這warning是因為在 Windows 中的換行符號為 CRLF,Git 會在你提交的時候自動將 CRLF 轉換成 LF,而在 checkout 時將 LF 轉換成 CRLF,[不建議關閉](https://shazi.info/git-%E5%9C%A8-windows-%E9%80%B2%E8%A1%8C-add-%E5%87%BA%E7%8F%BE%E8%AD%A6%E5%91%8A%E3%80%8Cwarning-lf-will-be-replaced-by-crlf%E3%80%8D/)
> 再次檢視`git status`
```git=
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: welcom.html
Untracked files:
.... 省略
```
:waning_crescent_moon: `welcom.html`的狀態從`Untracked` 變成 `new file`,表示這個檔案被放到==暫存區(Staging Area)==,等待稍後跟其它檔案一起被存到儲存庫裡
> 可以一次把多個檔案提交,例如
>
```git=
$ git add *.py
s710262101@ios7188-826 MINGW64 /e/我的雲端硬碟/drive/190614師兄打卡系統/code (master)
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: data_tosql.py
new file: database_connection.py
new file: pyqt5_main.py
new file: sqlite_op.py
new file: welcom.html
```
:::warning
一次提交目錄裡面所有檔案到暫存區
`$ git add --all`
:::
:::info
**【狀況題】如果在 git add 之後又修改了那個檔案的內容?**
想像一下這個情境:
你新增了一個檔案叫做 `abc.txt`。
然後,執行 `git add abc.txt` 把檔案加至暫存區。
接著編輯 `abc.txt` 檔案。
完成編輯後,接著你可能會想要進行 `Commit`,把剛剛修改的內容存下來。這是新手可能會犯的錯誤之一,以為 `Commit` 指令就會把所有的異動都存下來,事實上這樣的想法是不太正確的。執行一下 `git status` 指令,看一下目前的狀態:
```git=
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: abc.txt
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: abc.txt
```
結果會發現 `abc.txt` 這個檔案變成 2 個了。因為在第 2 步的確有把 abc.txt 加到暫存區,但在第 3 步又編輯了那個檔案,對 Git 來說,編輯的內容並==沒有再次被加到暫存區==,所以這時候在暫存區裡的資料還是你在第 2 步時候加進來的那個檔案。
如果確定這個修改必須再次使用 `git add abc.txt` 指令,再把 `abc.txt` 加至暫存區。
:::
## `git commit` 暫存區到倉庫(Git Repository)
要讓暫存區的內容永久的存下來的話,使用的是 `git commit` 指令:
```git=
$ git commit -m "init commit"
[master (root-commit) d2f4c62] init commit
5 files changed, 560 insertions(+)
create mode 100644 data_tosql.py
create mode 100644 database_connection.py
create mode 100644 pyqt5_main.py
create mode 100644 sqlite_op.py
create mode 100644 welcom.html
```
:waning_crescent_moon: `-m "init commit"`是要說明這次commit所做的更動
:warning: 要完成 Commit 指令才算完成整個流程
## 關於 `git commit`..
### 什麼東西會被commit到Repository
==「Git 每次的 Commit 都*只*會處理暫存區(Staging Area)裡的內容」==。也就是說,如果在執行 `git commit` 指令的時候,那些還沒被加到暫存區裡的檔案,就不會被 Commit 到儲存庫裡。
### commit的說明訊息
在 Commit 的時候,如果沒有輸入這個訊息,Git 預設是不會讓你完成 Commit 這件事的。它最主要的目的就是告訴你自己以及其它人「這次的修改做了什麼」。以下是幾點關於訊息的建議:
1. 英文、中文都沒關係,重點是要簡單、清楚。
2. 儘量不要使用像 bug fixed 這樣模糊的描述,因為沒人知道你修了什麼 bug。但如果有搭配其它的系統使用,則可使用 #34 bug fixed,因為這樣可以知道這次的 Commit 修正了第 34 號的 bug。
:warning: 只要加上 `--allow-empty` 參數,沒東西也可以 Commit (不建議)
```git=
$ git commit --allow-empty -m "空的"
[master 76a5b84] 空的
```
# 工作區、暫存區與儲存庫
在 Git 裡,主要可以分成「工作目錄(Working Directory)」、「暫存區(Staging Area)」以及「儲存庫(Repository)」三個區塊,透過不同的 Git 指令,可以把檔案移往不同的區域:
1. `git add` 指令把檔案從工作目錄移至暫存區(或索引)。
2. `git commit` 指令把暫存區的內容移至儲存庫。

## 一段式commit法
在 Commit 的時候多加一個 `-a` 的參數,縮短這個流程:
> 先修改`welcom.html`的內容
```git=
$ echo 'text here' >> welcom.html
```

> 一段式commit
```git=
$ git commit -a -m 'update content'
warning: LF will be replaced by CRLF in welcom.html.
The file will have its original line endings in your working directory
[master d219677] update content
1 file changed, 1 insertion(+)
```
:waning_gibbous_moon: 只有一個檔案有變更,因此只有`welcom.html`重新commit
:::info
==為何需要二段式commit==
當然,你也可以每來一件貨物就開倉門存一次、紀錄一次,但這樣一來開倉庫的次數就會非常多。老實說這樣也沒什麼過錯,只是因為太過零碎的 Commit,有時候要查閱紀錄可能會有點不太方便;另外,過於零碎的 Commit 也可能給你的同事帶來一些困擾,例如要進行 Code Review 的時候,比較有整理的 Commit 可以一次看到比較完整的內容,而不需要一個一個 Commit 慢慢看。
:::
:::info
==何時commit==
這個問題沒有標準答案,你可以很多檔案修改好再一口氣全部一起 Commit,也可只改一個字就 Commit。常見的 Commit 的時間點有:
1. 完成一個「任務」的時候:不管是大到完成一整個電子商務的金流系統,還是小至只加了一個頁面甚至只是改幾個字,都算是「任務」。
2. 下班的時候:雖然可能還沒完全搞定任務,但至少先 Commit 今天的進度,除了備份之外,也讓公司知道你今天有在努力工作。(然後帶回家繼續苦命的做?)
3. 你想要 Commit 的時候就可以 Commit。
:::
## vscode storage & commit
> 這個檔案目前的狀態`U`表示尚未被追蹤

> 加入 storage

> 可以一次加入所有檔案到 Staging Area

> 加入成功後的狀態變成下圖這樣,接著commit

<br/>
<br/>
#### Inline Blame Annotations
如果有裝 `GitLens`插件 commit後可以直接在檔案內該行,看到commit的時間跟commit的資訊

:waning_crescent_moon: 這功能非常方便,可以很快地找到這行code的始作用者,正確找到要幹譙的人
> 如果繼續修改檔案,左邊綠色的highlight表示這些內容還還沒有commit。右側也能看到文字說明

> 儲存一下,檢視source control的內容
> 
:waning_crescent_moon: `M`表示這個檔案被修改,但尚未commit
> 第二次commit後回到script檢視修改歷史


:waning_crescent_moon: 可以很方便的檢視每次commit到底做了什麼
# 檢視紀錄
>先再進行一次commit比較熱鬧
>
```git=
$ touch index.html
$ git add "index.html"
$ git commit -m "create index page"
[master a100b63] create index page
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 index.html
```
## `git log`檢視紀錄
新的資訊會先print出來
結果包含三個重要的資訊:
1. commit的作者
2. 什麼時候commit的
3. 做了什麼(說明)
```git=
$ git log
commit a100b631386426b6215be3d24f044324cf096679 (HEAD -> master)
Author: Lee TsungTang <s710262101@gm.ntpu.edu.tw>
Date: Thu Oct 24 16:23:20 2019 +0800
create index page
commit d21967747b8d0966663a1c0e4e278a4f9cfca414
Author: Lee TsungTang <s710262101@gm.ntpu.edu.tw>
Date: Thu Oct 24 16:11:45 2019 +0800
update content
commit d2f4c6210bc50da8bcb0078828a13b3336e271a5
Author: Lee TsungTang <s710262101@gm.ntpu.edu.tw>
Date: Thu Oct 24 15:43:56 2019 +0800
init commit
```
:waning_crescent_moon: commit 內的內容可以看做是該次commit的==UID==
> 用`--oneline` 跟 `--graph`這兩個參數讓輸出的結果更精簡
```git=
$ git log --oneline --graph
* a100b63 (HEAD -> master) create index page
* d219677 update content
* d2f4c62 init commit
```
### 查看特定author的commit `--author`
> `--author='author name'`查找特定的commit
```git=
$ git log --oneline --author='Lee TsungTang'
a100b63 (HEAD -> master) create index page
d219677 update content
d2f4c62 init commit
$ git log --oneline --author='hhh'
```
:waning_crescent_moon: 由於沒有其他作者,因此隨便寫一個不存在的author測試。結果不會返回任何commit
> 可以再用 `|` 來查詢不同人的 Commit 紀錄」:
例如
```git=
$ git log --oneline --author="Sherly\|Eddie"
```
### 查找特定的commit說明訊息的內容 `--grep`
> 查找有"update"的commit
```git=
$ git log --oneline --grep='update'
d219677 update content
```
<!-- ### 查找特定commit檔案內的文字 `-S` -->
### 查找特定時間的commit `--since` `--until` `--after`
```git=
$ git log --oneline --since='16:30pm' --until='17pm'
4fc4856 (HEAD -> master) add text in index page
```
## VScode git log
### 查看整體紀錄
先安裝`Git history`插件
> vscode的Command Palette `ctrl` + `shift` + `p`
> 輸入git找到下面這個,然後點進去

> 進入histroy頁面,這個頁面可以檢視每次commit的內容、分支、作者......所有你想知道關於commit的資訊

> 例如檢視某次commit狀態下某個檔案的內容

### 檢視特定檔案的變更歷程
|方法1|方法2|
|-|-|
|||
> 檢視檔案每一次commit做了什麼更動

# 在Git裡刪除檔案或變更檔名
在 Git 裡,不管是刪除檔案或是變更檔名,對 Git 來說都是一種「修改」。
## 刪除檔案 `rm`
> 嘗試刪除'welcom.html'
```git=
$ rm welcom.html
s710262101@ios7188-826 MINGW64 /e/我的雲端硬碟/drive/190614師兄打卡系統/code (master)
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: welcom.html
```
:waning_crescent_moon: 'welcom.html'的狀態變為`deleted`
> 如果確定此次修改則加到暫存區
>
```git=
$ git add welcom.html
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
deleted: welcom.html
```
> 接著commit
>
```git=
$ git commit -m 'delete welcom.html'
[master 54fd25b] delete welcom.html
1 file changed, 4 deletions(-)
delete mode 100644 welcom.html
```
:warning: 在git追蹤的狀況下「刪除檔案」也當做是一種「修改」看待就行了。
## 用 Git 刪除檔案 `git rm`
`git rm` = `rm` + `git add`
```git=
$ git rm welcome.html
rm 'welcome.html'
```
:waning_crescent_moon: 只要再commit就可以完成了
### `–cached` 參數
`--cached`參數不會直接刪掉檔案,而是能讓檔案不被git控管
:watch: 下面這段沒有真的跑
```git=
$ git rm welcome.html --cached
rm 'welcome.html'
```
> welcome.html 的狀態從原本已經在 Git 目錄裡的 tracked 變成 Untracked 了。
```git=
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: welcome.html
Untracked files:
(use "git add <file>..." to include in what will be committed)
welcome.html
```
### `git checkout`救回被刪除的檔案
```git=
# 準備檔案
$ echo 'text here' >> 'index.html'
$ git add 'index.html'
$ git commit -m 'modified index.html for test'
```
> 刪除`index.html`
```git=
$ rm index.html
$ ls
__pycache__/ data_tosql.py desktop.ini layout_test.py pyqt5.spec pyqt5_main.spec test.db
build/ database_connection.py dist/ punchSystem-7c27e17aa7de.json pyqt5_main.py sqlite_op.py TEST.html
```
> 確認`git status`
```git=
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: index.html
...
```
:waning_crescent_moon: `index.html`處於deleted狀態
> `git checkout`救回檔案
```git=
$ git checkout index.html
Updated 1 path from the index
$ ls -al
...
-rw-r--r-- 0 s710262101 1049089 5 十一月 14 16:41 index.html
...
```
:waning_gibbous_moon: 成功
> 理論上不要刪掉git 目錄都能夠把檔案救回來
## 變更檔名
### 直接改名
```git=
$ mv hello.html world.html # 把 hello.html 改成 world.html
```
## 修改 Commit 紀錄
要修改 Commit 紀錄有好幾種方法:
1. 把 `.git` 目錄整個刪除(no!)。
2. 使用 `git rebase` 來修改歷史。
3. 先把 Commit 用 `git reset` 拆掉,整理後再重新 Commit。
4. :hash: 使用 `--amend` 參數來修改最後一次的 Commit。
:waning_crescent_moon: 此處介紹第4種
```git=
$ git log --oneline
54fd25b (HEAD -> master) delete welcom.html
4fc4856 add text in index page
a100b63 create index page
d219677 update content
d2f4c62 init commit
```
>`--amend`參數修正最新一次commit的訊息
```git=
$ git commit --amend -m "delete welcom.html2"
[master b872268] delete welcom.html2
Date: Thu Oct 24 17:41:44 2019 +0800
1 file changed, 4 deletions(-)
delete mode 100644 welcom.html
```
> 成功改為 "delete welcom.html2"
```git=
$ git log --oneline
b872268 (HEAD -> master) delete welcom.html2
4fc4856 add text in index page
a100b63 create index page
d219677 update content
d2f4c62 init commit
```
:::warning
雖然只是改紀錄的訊息,但對 Git 來說因為「Commit 的內容」改變了,所以 Git 會重新計算並產生一顆新的 `Commit` 物件,也就是這其實是一次==全新的 Commit==(只是看起來不像新的)。以上面這個例子為例,修改前的 Commit 物件的 SHA-1 值是 54fd25b,但改完訊息之後 SHA-1 值變成 b872268。雖然 Commit 的時間跟檔案的內容看起來並沒有被修改,但它仍是一次全新的 Commit。
:::
:warning: 通常會避免在`push`後修改
## 追加commit 檔案
1. 使用 git reset 把最後一次的 Commit 拆掉,加入新檔案後再重新 Commit。
2. 使用 --amend 參數進行 Commit。
```git=
$ git add cinderella.html # 新檔案
$ git commit --amend --no-edit
```
:waning_crescent_moon: `--no-edit` 是不編輯commit訊息
## 檢視特定檔案的 Commit 紀錄
`git log` + 檔名檢視單一檔案的紀錄
```git=
$ git log pyqt5_main.py
commit 9f0f8ac26249edef2fccc9ae221a95281f13a032 (HEAD -> master)
Author: Lee TsungTang <s710262101@gm.ntpu.edu.tw>
Date: Thu Nov 14 14:32:14 2019 +0800
dynamic add punch widget
commit 0e8612ec0a45320b0503e01eea75582ac3ceb5c6
Author: Lee TsungTang <s710262101@gm.ntpu.edu.tw>
Date: Wed Nov 6 21:04:07 2019 +0800
補打卡widgets完成
commit d2f4c6210bc50da8bcb0078828a13b3336e271a5
Author: Lee TsungTang <s710262101@gm.ntpu.edu.tw>
Date: Thu Oct 24 15:43:56 2019 +0800
init commit
```
> `-p` 參數可以看每次做了什麼修改
>
## 退回到哪次commit前的結果
`git reset`
> 先弄一個新的檔案,並commit。等等準備拆掉
```git=
$ echo "test, git" > TEST.html
$ git add "TEST.html"
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: TEST.html
...
$ git commit -m "準備被拆掉的test檔"
[master 7c6139d] 準備被拆掉的test檔
1 file changed, 1 insertion(+)
create mode 100644 TEST.html
```
> 檢視一下紀錄
```git=
git log
commit 7c6139d881c39b31af73bc4a8186c0e77ccdcbb5 (HEAD -> master)
Author: Lee TsungTang <s710262101@gm.ntpu.edu.tw>
Date: Thu Nov 14 15:38:40 2019 +0800
準備被拆掉的test檔
...
```
### 相對位置
```git=
$ git reset 7c6139d^ # not run
```
:waning_crescent_moon: `^`表示要拆掉`7c6139d`前一次commit,如果要再往前拆可以用`^^`(往前2個commit),`7c6139d~5`(往前5個commit)
> 因為目前的HEAD與master都指向`7c6139d`這個commit,因此上面這行也可以寫為
>
```git=
$ git reset master^ # not run
$ git reset HEAD^ # not run
```
### 絕對位置
如果知道要退回哪次commit的狀態,可以直接指定:
```git=
$ git reset 9f0f8ac
# 檢視一下結果
$ git log --oneline
9f0f8ac (HEAD -> master) dynamic add punch widget
0e8612e 補打卡widgets完成
b872268 delete welcom.html2
4fc4856 add text in index page
a100b63 create index page
d219677 update content
d2f4c62 init commit
```
:waning_crescent_moon: 成功退回前一次的commit
## reset的三種模式
- `--mixed`、`--soft` 以及 `--hard`
> 預設為`--mixed`
>
模式 |mixed 模式 |soft 模式 |hard 模式
|--|--|--|--|
工作目錄|不變|不變|丟掉
暫存區|丟掉|不變|丟掉
Commit 拆出來的檔案|丟回工作目錄|丟回暫存區|直接丟掉
:waning_crescent_moon: 因此預設的`--mixed`操作後,`TEST.html`檔案其是還在資料夾的目錄區內
事實上git拆掉的commit 以及丟掉的檔案也可以救回來(即使是`--hard`模式),因為`git reset`在git的概念中比較像往前回到某個狀態,所以當然也可以再往後回到某個狀態
# 分支
一個人開發時一直commit沒有太大問題,但當多人在同一個專案工作的時候,可能就不能這麼隨興的想 Commit 就 Commit,這時候分支就很好用。例如想要增加新功能,或是修正 Bug,或是想實驗看看某些新的做法,都可以另外做一個分支來進行,待做完確認沒問題之後再合併回來,不會影響正在運行的產品線。
在多人團隊共同開發的時候,甚至也可引入像 Git Flow / GitHub Flow / GitLab Flow 之類的開發流程,讓同一個團隊的人都可以用相同的方式進行開發,減少不必要的溝通成本。
## `git branch` 檢視當前分支
> `git branch` 後面沒接任何參數,會檢視目前在哪一個分支
```git=
git branch
* master
```
:waning_gibbous_moon: 前面的星號 ==*== 表示現在正在這個分支上。
## `git branch <branch name>` 新增分支
> git branch後加上文字創造新分支 cat
```git=
git branch cat
git branch
cat
* master
```
:waning_crescent_moon: master為當前分支
## `git branch -m <original name> <new name>` 分支換名稱
> cat rename為 tiger
```git=
git branch -m cat tiger
git branch
tiger
dog
* master
```
### vscoed 開啟及切換分支
> 左下角點選==master== (master表示現在的分支)

> 選擇 Create new branch from 再選擇master

:waning_crescent_moon: Create new branch會以當前分支創建新分支
> 輸入新branch name

> 創建成功
> 
## `git branch -d <branch name>` 刪除分支
```git=
$ git branch -d dog
Deleted branch dog (was e12d8ef).
$ git branch
cat
* master
```
:::success
如果要刪的分支還沒被完全合併,Git 會有貼心小提示:
error: The branch 'dog' is not fully merged.
If you are sure you want to delete it, run 'git branch -D cat'.
如果要強制刪除可以改用`-D參數`
:::
## `git checkout` 切換分支
```git=
git checkout cat
Switched to branch 'cat'
git branch
* cat
dog
master
```
### Vscode切換分支
> 可以點選cat branch

> 選擇要切換的分支
> 
## 在分支中commit
```git=
$ git checkout tiger
Switched to branch 'tiger'
$ touch cat1.html
$ git add cat1.html
$ git commit -m "add cat 1"
[tiger 9419c7d] add cat 1
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 cat1.html
$ touch cat2.html
$ git add cat2.html
$ git commit -m "add cat 2"
[tiger ceb6856] add cat 2
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 cat2.html
$ git log --oneline
ceb6856 (HEAD -> tiger) add cat 2
9419c7d add cat 1
60e3c29 (master) secound commit
7694dc1 first commit
```
:waning_crescent_moon: 分支commit的進度比master快了兩次
> 檢視此時的檔案
```git=
$ ls -al
total 2
-rw-r--r-- 0 s710262101 1049089 0 十二月 14 13:24 cat1.html
-rw-r--r-- 0 s710262101 1049089 0 十二月 14 13:46 cat2.html
-rw-r--r-- 0 s710262101 1049089 32 十二月 13 11:02 welcom.html
```
:waning_gibbous_moon: 多了`cat1.html` `cat2.html`
> 切回master檢視
```git=
$ git checkout master
Switched to branch 'master'
$ ls -al
total 2
-rw-r--r-- 0 s710262101 1049089 32 十二月 13 11:02 welcom.html
```
:warning: master裡面不會有剛剛在分支中新增的檔案,除非切回分支
### Vscode中檢視分支
> `ctrl` + `shift` + `p` 開啟command palette,搜尋git history

> 在`master` 分支中只會看到此分支中的commit
> 
> 如果切換到`tiger`分支則能看到前面的commit歷程(包括master)

#### view git graph
如果有裝了Git Graph 插件,能提供另一種視覺化的git log


> 同樣可以檢索每次commit的資訊與檔案
> 
:waning_crescent_moon: Git Graph 支援即時更新,所以有時候滿方便的
## `git merge <branch name>`合併分支
> master 分支來合併 tiger 分支,先切回 master 分支:
```git=
$ git checkout master
Switched to branch 'master'
$ git merge tiger
Updating 60e3c29..ceb6856
Fast-forward
cat1.html | 0
cat2.html | 0
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 cat1.html
create mode 100644 cat2.html
```
> 檢視 master裡面的檔案
```git=
$ ls -al
total 2
-rw-r--r-- 0 s710262101 1049089 0 十二月 14 15:07 cat1.html
-rw-r--r-- 0 s710262101 1049089 0 十二月 14 15:07 cat2.html
-rw-r--r-- 0 s710262101 1049089 32 十二月 13 11:02 welcom.html
```
:waning_crescent_moon: `cat1.html` `cat2.html` 出現在master裡面
### vscode 中 merge branch
> 一樣在command palette 裡面搜尋 git merge


> 合併完成後檢視 git graph
> 
:waning_crescent_moon: 本來落後 2 個 Commit 的 master 分支,在進行合併之後,進度已經跟上 tiger 分支,跟它在同一個 Commit 上
> 理論上這時候兩個分支已經沒有分別了,可以刪除舊有的分支
```git=
$ git branch -d tiger
Deleted branch tiger (was ceb6856).
```
```git=
git log -p pyqt5_main.py
commit 9f0f8ac26249edef2fccc9ae221a95281f13a032 (HEAD -> master)
Author: Lee TsungTang <s710262101@gm.ntpu.edu.tw>
Date: Thu Nov 14 14:32:14 2019 +0800
dynamic add punch widget
diff --git a/pyqt5_main.py b/pyqt5_main.py
index 86aadc4..e14d4ab 100644
--- a/pyqt5_main.py
+++ b/pyqt5_main.py
@@ -13,7 +13,7 @@ from sqlite_op import *
class App(QMainWindow):
choice = '米開朗基羅廳'
- choice_list = ['蘇格拉底廳', '洛克廳', '米開朗基羅廳', '國際會議廳B','柏拉圖廳','國際會議廳A','亞歷山大廳', '補打卡']
+ choice_list = ['蘇格拉底廳', '洛克廳', '國際會議廳B','柏拉圖廳','國際會議廳A','亞歷山大廳', '補打卡']
.. 太長省略
```
# Github
## git push 上傳專案到github
> 先開一個新的repository
>

> setup 頁面

### 說明:
1. 如果是全新開始,請依「create a new repository on the command line」的內容指示進行;如果是要上傳現存專案,則依照「push an existing repository from the command line」選項進行。
2. 畫面中間上面,有兩個按鈕可以切換,分別是「HTTPS」以及「SSH」。至於要選擇哪一個可看個人喜好,但選擇 SSH 的話需要設定 SSH Key。
<br>
> 要推上遠端git伺服器需要先設定端點的節點,例如
```git=
git remote add origin
git@github.com:kaochenlong/practice-git.git
```
> - `git remote` 指令主要是跟遠端有關的操作。
- add 指令是指要加入一個遠端的節點。
- 這裡的 origin 是一個「代名詞」,指的是後面那串 GitHub 伺服器的位置。(可以自行變更)
> push
```git=
$ git push -u origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 228 bytes | 228.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To github.com:kaochenlong/practice-git.git
* [new branch] master -> master
Branch master set up to track remote branch master from origin.
```
> -u 後的兩個參數分別為 <遠端位置><本地分支>
>

> success
# 參考資料
[Git book](https://zlargon.gitbooks.io/git-tutorial/content/)
[為自己學Git](https://gitbook.tw/chapters/command-line/command-line.html)
[Pro Git](https://git-scm.com/book/zh-tw/v2)
[30 天精通 Git 版本控管](https://github.com/doggy8088/Learn-Git-in-30-days/blob/master/zh-tw/README.md)