---
title: Astro課程 0629 - Git
tags: astro, git
---
[git 練習場](https://learngitbranching.js.org/?locale=zh_TW)
[git interview問題](https://gitbook.tw/interview)
# Astro課程 0629-0701 git
## 使用brew 安裝
```
tingtinghsu@Hui-TingdeMacBook-Air % which brew (這個指令在哪裡)
/usr/local/bin/brew
```
## 確認git版本
```
tingtinghsu@Hui-TingdeMacBook-Air % git --version
git version 2.24.0
```
## 初次設定git
```
git config --list
git config --global user.name "tingtinghsu"
git config --global user.email "tingtinghsu.tw[at]gmail.com"
```
注意:早期的時候寄email是不需要密碼的
也可以把以上指令中的global換成local,不同專案用不同公司/email
(因為不想發現是誰做的,統包商vs其他承包商)
cd /tmp (把資料放在/tmp,重開機就不見了)
## `git init`
告訴git, 以後這個資料夾就是我管!
```
tingtinghsu@Hui-TingdeMacBook-Air projects % mkdir gitdemo
tingtinghsu@Hui-TingdeMacBook-Air projects % cd gitdemo
tingtinghsu@Hui-TingdeMacBook-Air gitdemo % pwd
/Users/tingtinghsu/Documents/projects/gitdemo
tingtinghsu@Hui-TingdeMacBook-Air gitdemo % git init
Initialized empty Git repository in /Users/tingtinghsu/Documents/projects/gitdemo/.git/
```
`.git` 所有紀錄都會在裡面
小技巧:不要給廠商 `.git`檔
(拿到肉體,不要給靈魂(對方歷史紀錄))
發案方(甲方)記得拿到歷史紀錄

[Reference](https://ithelp.ithome.com.tw/articles/10211058)
儲存庫(遠端)

CRUD 新增讀取修改刪除
## git status
```
tingtinghsu@Hui-TingdeMacBook-Air gitdemo % touch first_day.rb
tingtinghsu@Hui-TingdeMacBook-Air gitdemo % git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
first_day.rb
```
## git add
```
tingtinghsu@Hui-TingdeMacBook-Air gitdemo % touch second_day.rb
tingtinghsu@Hui-TingdeMacBook-Air gitdemo % git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
#變成兩個檔案
first_day.rb
second_day.rb
tingtinghsu@Hui-TingdeMacBook-Air gitdemo % git add first_day.rb
tingtinghsu@Hui-TingdeMacBook-Air gitdemo % git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: first_day.rb
Untracked files:
(use "git add <file>..." to include in what will be committed)
second_day.rb
```
## `git rm -cached` 復原staging的狀態
使用`git rm -cached 檔案名稱`將暫存區域的檔案移回工作目錄
```
tingtinghsu@Hui-TingdeMacBook-Air gitdemo % git rm --cached first_day.rb
rm 'first_day.rb'
tingtinghsu@Hui-TingdeMacBook-Air gitdemo % git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
first_day.rb
second_day.rb
```
## `git commit -m "<寫入訊息>"`
使用 `git commit -m "簡述此次修改的內容"` 將資料推入儲存庫,此語法是一個歸檔的動作,敘述修改內容有助於之後的閱讀
**(如果只輸入git commit 會進入 vim畫面)**
```
tingtinghsu@Hui-TingdeMacBook-Air gitdemo % git commit -m "first day in Astro"
[master (root-commit) 0eca0f5] first day in Astro
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 first_day.rb
create mode 100644 second_day.rb
```
什麼時候要commit?
- 下班了
- 功能做到一個段落
## `git log`, `git log --oneline`
`git log`會顯示`commit`的作者、代碼及修改時間
`git log --oneline`將上述內容簡化成一行(不顯示作者)
```
tingtinghsu@Hui-TingdeMacBook-Air gitdemo % git log
commit c3c15882363d0e28f0b9180a80094ad8e6eb396e (HEAD -> master)
Author: tingtinghsu <tingtinghsu.tw@gmail.com>
Date: Mon Jun 29 15:56:24 2020 +0800
edit file using vim
commit 0eca0f50a4d69facf96c5d395621b3f69e497ee4
Author: tingtinghsu <tingtinghsu.tw@gmail.com>
Date: Mon Jun 29 15:42:31 2020 +0800
tingtinghsu@Hui-TingdeMacBook-Air gitdemo % git log --oneline
c3c1588 (HEAD -> master) edit file using vim
0eca0f5 first day in Astro
```
重要!`git add .`和 `git add --all`會將**所有**在工作目錄的檔案加入至暫存區域,範圍影響太大,盡量不要使用
# Git 小劇場
## `git restore 檔名`
可將刪掉之後的檔案拿回來
```
tingtinghsu@Hui-TingdeMacBook-Air projects % cd git-examples
tingtinghsu@Hui-TingdeMacBook-Air git-examples % ls
git-branch1 git-branch3 git-rebase
git-branch2 git-conflict git-stash
tingtinghsu@Hui-TingdeMacBook-Air git-examples % cd git-branch1
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % ls
config hello.html index.html welcome.html
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % rm index.html
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % ls
config hello.html welcome.html
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git restore index.html
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % ls
config hello.html index.html welcome.html
```
## `git restore` 和 `git checkout` 的不同
`git checkout`
=> 有可能是兩種選項
`git restore` (刪掉儲存的檔案)
`git switch` (切換分支)
```
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git branch
* cat
master
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git help checkout
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % ls
config hello.html index.html welcome.html
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % touch cat
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % ls
cat config hello.html index.html welcome.html
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git rm cat
fatal: pathspec 'cat' did not match any files
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git checkout cat
Already on 'cat'
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git checkout master
Switched to branch 'master'
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % ls
cat config hello.html index.html welcome.html
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git branch
cat
* master
```
## `git help checkout` 可以查詢指令
`git checkout .` (回歸到最近的一次commit狀態)
SL 大法: Save and load
`git restore .`
註:`git checkout`和`git reset`也容易混淆!請參考[細說git reset和git checkout的不同之處](https://medicineyeh.wordpress.com/2015/01/22/%E7%B4%B0%E8%AA%AAgit-reset%E5%92%8Cgit-checkout%E7%9A%84%E4%B8%8D%E5%90%8C%E4%B9%8B%E8%99%95/)
## `git`壞掉了,這行是誰寫的?
`git blame 檔名`
罵人之前先檢查,阿老師說吼通常會blame到自己
```
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git blame index.html
abb4f438 (Eddie Kao 2017-08-02 16:49:49 +0800 1) <!DOCTYPE html>
abb4f438 (Eddie Kao 2017-08-02 16:49:49 +0800 2) <html>
abb4f438 (Eddie Kao 2017-08-02 16:49:49 +0800 3) <head>
abb4f438 (Eddie Kao 2017-08-02 16:49:49 +0800 4) <meta charset="utf-8">
abb4f438 (Eddie Kao 2017-08-02 16:49:49 +0800 5) <title>首頁</title>
abb4f438 (Eddie Kao 2017-08-02 16:49:49 +0800 6) </head>
abb4f438 (Eddie Kao 2017-08-02 16:49:49 +0800 7) <body>
657fce78 (Eddie Kao 2017-08-02 16:53:43 +0800 8) <div class="container">
657fce78 (Eddie Kao 2017-08-02 16:53:43 +0800 9) </div>
abb4f438 (Eddie Kao 2017-08-02 16:49:49 +0800 10) </body>
abb4f438 (Eddie Kao 2017-08-02 16:49:49 +0800 11) </html>
```
## `git log -p` 單一檔案的歷史紀錄
```
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git log -p index.html
commit 657fce783a23e26721ec4f778b9e0e108253e92d
Author: Eddie Kao <eddie@5xruby.tw>
Date: Wed Aug 2 16:53:43 2017 +0800
add container
diff --git a/index.html b/index.html
index d1146e2..e90bdb3 100644
--- a/index.html
+++ b/index.html
@@ -5,5 +5,7 @@
<title>首頁</title>
</head>
<body>
+ <div class="container">
+ </div>
</body>
</html>
commit abb4f43814af7bcf47afa9b779aaba63599e562b
Author: Eddie Kao <eddie@5xruby.tw>
Date: Wed Aug 2 16:49:49 2017 +0800
```
# `git branch` 分支
關鍵下一秒 (Next, 2007)
男主角可以看到不久之後的未來
未來 git master 可能會改成 git main (?)
# `git head`
* HEAD 現在
磁頭指的地方就是現在所在的分支上
分支指是一張貼在某個`commit`上的貼紙
分支往前移動,被HEAD(空心小圈圈)指的貼紙就往前貼
要先把權杖/令牌交給分身(HEAD,空心小圈圈),再叫分身去做事
```
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git branch cat
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git status
On branch master
nothing to commit, working tree clean
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git branch
cat
* master
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git checkout cat
Switched to branch 'cat'
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git status
On branch cat
nothing to commit, working tree clean
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git branch
* cat
master
```
圖形不一定會開叉,因為設計概念是貼貼紙
剛開完分支時並沒有感覺到特別的變化
(就像原地跳起來、原地落下)
(回到主要分支的時候,其他分支上建立的東西不會被刪掉)
本體`master`盡量留在原地,不要往前移動;
讓分支往前移。
# Day2
## 狀況一:建立新分支,並將新分支的commit合併到主分支
**重要:合併分支可以視為移動貼紙!**
流程
1. `git branch cat`
建立新分支
2. `git checkout cat`
切換到新分支
3. `git commit -m "多一個commit" --allow-empty`
在新分支上`commit
--allow-empty`內容不一定要有檔案(這指令不太有意義,只是為了教學用)
4. `git checkout master`
切回主分支
6. `git merge cat`
主分支合併新分支
使用`Fast-forward 快轉模式`合併(收割成果)
練習:
```
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git status
On branch cat
Untracked files:
(use "git add <file>..." to include in what will be committed)
cat
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git add .
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git commit -m "add cat"
[cat 454e202] add cat
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 cat
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git branch
all
* cat
master
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git checkout master
Switched to branch 'master'
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git merge cat
Updating e12d8ef..454e202
Fast-forward
cat | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 cat
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git branch
all
cat
* master
```
## 狀況二:複雜一點的分支
- 開始跟別人合作
- 如果要把`cat`分支和`dog`分支合併在一起
(~~例如跟郭台銘合併家產~~)
Eg. 如何用`dog`分支去合併`cat`分支?
1. 長出一顆新的`commit` (合併用的節點)(~~公正的律師~~)
2. 被head指的`dog`貼紙往前移
註:`git merge`時盡量加上註解`-m " "`,不然會進入vim畫面
這次使用的`git merge`就不是`fast-forward`,而是`'recursive' strategy`
練習:
```
tingtinghsu@Hui-TingdeMacBook-Air git-examples % cd git-branch2
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git status
On branch master
nothing to commit, working tree clean
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git branch
cat
dog
* master
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git checkout dog
Switched to branch 'dog'
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git merge cat -m "dog branch merge cat"
Merge made by the 'recursive' strategy.
cat1.html | 0
cat2.html | 0
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 cat1.html
create mode 100644 cat2.html
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git branch
cat
* dog
master
```
不想要快轉合併,可以在指令加上`--no-ff`
(只是為了創造分支的存在感)
## 狀況三:刪掉已經合併過的分支
`git branch -d cat`
`git branch -D`
檔案沒有完全不見(所以可以救回來)
不管是FF合併或是Y型合併
- 歷史紀錄並不會消失 (因為是沒有人看管的末端枝節)
- 電腦多了40bytes (撕掉貼紙佔用的空間)
## 狀況四:忘記切換分支
只要想辦法把貼紙切換過來就可以
因為`git`的本體是`commit` (做了什麼事情),而不是貼紙的名字
名字互換:
```
git branch -m cat ccc (在master上改cat名字成ccc)
git checkout ccc
git branch -m master cat
git checkout cat
git branch -m ccc master
```
## 狀況五:發生衝突 Conflict
- 順利長出共同節點的前提是**沒有衝突**
- git沒有辦法解決conflict,但會標出conflict的地方
練習:不管是誰合併誰,都會產生衝突
```
tingtinghsu@Hui-TingdeMacBook-Air git-examples % cd git-conflict
tingtinghsu@Hui-TingdeMacBook-Air git-conflict % git status
On branch payment
nothing to commit, working tree clean
tingtinghsu@Hui-TingdeMacBook-Air git-conflict % git branch
master
member
* payment
tingtinghsu@Hui-TingdeMacBook-Air git-conflict % git merge member
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
```
- 解決衝突並不一定代表解決問題
=> 如果沒有修好出現conflict的程式碼就直接`commit`,問題還是沒有解決
=> 去找同事討論該如何修改程式產生衝突的地方再commit
```
tingtinghsu@Hui-TingdeMacBook-Air git-conflict % git checkout member
index.html: needs merge
error: you need to resolve your current index first
tingtinghsu@Hui-TingdeMacBook-Air git-conflict % git status
On branch payment
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Changes to be committed:
new file: member.html
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.html
tingtinghsu@Hui-TingdeMacBook-Air git-conflict % git add .
tingtinghsu@Hui-TingdeMacBook-Air git-conflict % vim index.html
tingtinghsu@Hui-TingdeMacBook-Air git-conflict % git commit -m "remove payment link"
[payment 031dc59] remove payment link
tingtinghsu@Hui-TingdeMacBook-Air git-conflict % git merge member
Already up to date.
tingtinghsu@Hui-TingdeMacBook-Air git-conflict % git status
On branch payment
nothing to commit, working tree clean
```
# rebase
- rebase:把Y型分支拉直(複製一份分支再嫁接的概念)
- rebase發生衝突時,先解決衝突,再continue
## rebase與merge的差別
優點
- 省一顆commit的節點
- 讓合併的歷史紀錄`分支樹`變得比較`瘦`、`精簡`
缺點
- 比較麻煩
- 歷史紀錄不會保留(但這可能也是優點)
練習:
```
tingtinghsu@Hui-TingdeMacBook-Air git-examples % cd git-branch2
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git status
On branch dog
nothing to commit, working tree clean
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git checkout cat
Switched to branch 'cat'
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git status
On branch cat
nothing to commit, working tree clean
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git rebase dog
First, rewinding head to replay your work on top of it...
Fast-forwarded cat to dog.
```
什麼時候適合用rebase?
- 用來整理自己的commit
- 分叉的地方對其他人不太有意義的時候
# reset
## 當做好的commit不太滿意,想要砍掉
`git reset "commit的id"`
(reset有become的意思)
後面接的三種參數:
決定被砍掉的commit要被丟到哪裏
```
--soft (暫存區)
--mixed (預設值,放在工作目錄)(比soft多了git add指令)
--hard (拋棄)
```
練習:
```
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git log --oneline
454e202 (HEAD -> master, cat, all) add cat
e12d8ef add database.yml in config folder
85e7e30 add hello
657fce7 add container
abb4f43 update index page
cef6e40 create index page
cc797cd init commit
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git reset 657fce7
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git log --oneline
657fce7 (HEAD -> master) add container
abb4f43 update index page
cef6e40 create index page
cc797cd init commit
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
cat
config/
hello.html
```
比較常用代名詞 (master, cat, HEAD)
## `git reset HEAD --hard`
我想回到現在這個地方
(修改過但還沒commit的變化,全部都不要了)
> ^ = caret 卡洛特
~ = tilde 提爾達
^ 倒退一步
^^ 倒退二步
~10 倒退10步
## `git reset HEAD^ --hard`
=> 類似ctrl Z
我想回到上一步 (但不能再回來了)
# checkout
## `reset` 跟`checkout`指令的差別?
`git checkout`: 我要去別的地方看一下
HEAD移動,`master`留在原地,所以分支的末端不會消失
`git reset`:
HEAD和master一起移動到之前的commit,分支的末端消失
練習:
1. `cat` 合併 `dog`
```
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git checkout cat
Switched to branch 'cat'
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git status
On branch cat
nothing to commit, working tree clean
# Merge branch dog into cat
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git merge dog
Merge made by the 'recursive' strategy.
dog1.html | 0
dog2.html | 0
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 dog1.html
create mode 100644 dog2.html
```
2. 把cat貼紙撕起來,貼回上一步的commit

git reset HEAD^ --hard (變回合併前的狀態)
```
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git log --oneline
28f7314 (HEAD -> cat) Merge branch 'dog' into cat
053fb21 (dog) add dog 2
b69eb62 add dog 1
b174a5a add cat 2
c68537b add cat 1
e12d8ef (master) add database.yml in config folder
85e7e30 add hello
657fce7 add container
abb4f43 update index page
cef6e40 create index page
cc797cd init commit
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git reset HEAD^ --hard
zsh: no matches found: HEAD^
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git reset HEAD\^ --hard
HEAD is now at b174a5a add cat 2
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git log --oneline
b174a5a (HEAD -> cat) add cat 2
c68537b add cat 1
e12d8ef (master) add database.yml in config folder
85e7e30 add hello
657fce7 add container
abb4f43 update index page
cef6e40 create index page
cc797cd init commit
```
[錯誤訊息:zsh: no matches found: HEAD^](https://github.com/ohmyzsh/ohmyzsh/issues/449)
## 狀況七:不小心用reset HARD模式刪掉commit
使用`git reflog`,然後hard reset回來
```
tingtinghsu@Hui-TingdeMacBook-Air git-examples % cd git-branch1
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git reset HEAD~5 --hard
HEAD is now at cc797cd init commit
```
刪掉只剩一個commit...該怎麼辦?

解法:找出HEAD的移動軌跡,包括
`checkout`
`commit`
`rebase`
`reset`
`merge`
```
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git reflog
cc797cd (HEAD -> master) HEAD@{0}: reset: moving to HEAD~5
e12d8ef HEAD@{1}: checkout: moving from cat to master
b174a5a HEAD@{2}: reset: moving to ORIG_HEAD
7243723 HEAD@{3}: rebase finished: returning to refs/heads/cat
7243723 HEAD@{4}: rebase: add cat 2
5b8f484 HEAD@{5}: rebase: add cat 1
053fb21 HEAD@{6}: rebase: checkout dog
b174a5a HEAD@{7}: checkout: moving from master to cat
e12d8ef HEAD@{8}: reset: moving to ORIG_HEAD
b174a5a HEAD@{9}: merge cat: Fast-forward
e12d8ef HEAD@{10}: reset: moving to ORIG_HEAD
...
```
找到`e12d8ef HEAD@{1}`的序號
`git reset e12d --hard`
```
tingtinghsu@Hui-TingdeMacBook-Air git-branch1 % git reset e12d --hard
HEAD is now at e12d8ef add database.yml in config folder
```
commit又全部長回來了!

註:`rm -rf .git` 才會砍掉所有紀錄
## 狀況八:不小心刪掉分支,如何復原?
刪掉dog分支的話,再把貼紙貼回去原來的commit就好
`git branch -d dog`
`git branch -D dog`
`git branch new_dog 053fb21`
(`git branch 分支名稱 想賦予名稱的commit id`)
```
tingtinghsu@Hui-TingdeMacBook-Air git-examples % cd git-branch2
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git branch -d dog
error: The branch 'dog' is not fully merged.
If you are sure you want to delete it, run 'git branch -D dog'.
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git branch -D dog
Deleted branch dog (was 053fb21).
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git reflog
e12d8ef (HEAD -> master) HEAD@{0}: checkout: moving from cat to master
b174a5a (cat) HEAD@{1}: reset: moving to ORIG_HEAD
...
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git branch new_dog 053f
```

冷知識:HEAD移動到不同分支上的commit節點
git checkout HEAD^1^2
= git checkout HEAD^^2
## 如何回到rebase之前的狀態?
1. 先rebase:
從cat分支:`git rebase dog`
(rebase current branch onto dog)
2. 再查詢當時分支存在的id:
`git reflog`
3. 然後用reset回復:
`git reset b174 --hard`
註:還可以繼續用reset `id`結果又回到剛才rebase的狀態!(~~方唐鏡~~)
=> 結論:reset可以用來做很多事!
# tag
`git tag 2.0`
(類似git branch 2.0的意思)
`git tag 1.0 abb4`
`cd -`: 回到上一動(上次的目錄)
所以`git checkout -`: 也是回到上一次路徑的意思
```
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git tag 2.0
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git tag 1.0 abb4
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git checkout 2.0
Note: switching to '2.0'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
HEAD is now at 053fb21 add dog 2
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git checkout 1.0
Previous HEAD position was 053fb21 add dog 2
HEAD is now at abb4f43 update index page
tingtinghsu@Hui-TingdeMacBook-Air git-branch2 % git checkout -
Previous HEAD position was abb4f43 update index page
HEAD is now at 053fb21 add dog 2
```
## tag和branch有什麼不同?
branch會跟著commit走
tag會留下來
「留下來,或者我跟你走!」
# 修改commit -m 的訊息
`git rebase bb0c -i` (interactive模式)
或者使用git GUI軟體,在commit的點上按右鍵操作


做過修改後,之後的子分支會產生平行時空(序號改變)
## 整合太瑣碎零散的commit
把add cat1 和 add cat2拆掉
squash with previous commit


修改後的commit,之後的序號都改了

## 拆掉很大一包的commit
1. 停下來: 先把HEAD指向需要修改的commit
2. 倒退一步 `git reset HEAD^`
3. 分別拆開檔案 `git add`
4. `git rebase --continue`
(但有接完壞掉的情況,取消 `git rebase --abort`)
```
tingtinghsu@Hui-TingdeMacBook-Air git-branch3 % cd ../git-rebase
tingtinghsu@Hui-TingdeMacBook-Air git-rebase % git status
interactive rebase in progress; onto bb0c9c2
Last commands done (2 commands done):
pick 382a2a5 add database settings
edit 3323ec7 All cat (+2 squashed commits) Squashed commits: [1de2076] add cat 2 [cd82f29] add cat 1
Next commands to do (5 remaining commands):
pick 4c5255f add dog 1
pick 1d68ddc add dog 2
(use "git rebase --edit-todo" to view and edit)
You are currently editing a commit while rebasing branch 'master' on 'bb0c9c2'.
(use "git commit --amend" to amend the current commit)
(use "git rebase --continue" once you are satisfied with your changes)
nothing to commit, working tree clean
tingtinghsu@Hui-TingdeMacBook-Air git-rebase % git reset HEAD\^
tingtinghsu@Hui-TingdeMacBook-Air git-rebase % git status
interactive rebase in progress; onto bb0c9c2
Last commands done (2 commands done):
pick 382a2a5 add database settings
edit 3323ec7 All cat (+2 squashed commits) Squashed commits: [1de2076] add cat 2 [cd82f29] add cat 1
Next commands to do (5 remaining commands):
pick 4c5255f add dog 1
pick 1d68ddc add dog 2
(use "git rebase --edit-todo" to view and edit)
You are currently editing a commit while rebasing branch 'master' on 'bb0c9c2'.
(use "git commit --amend" to amend the current commit)
(use "git rebase --continue" once you are satisfied with your changes)
Untracked files:
(use "git add <file>..." to include in what will be committed)
cat1.html
cat2.html
cat3.html
cat4.html
nothing added to commit but untracked files present (use "git add" to track)
tingtinghsu@Hui-TingdeMacBook-Air git-rebase % git add cat1 cat2
fatal: pathspec 'cat1' did not match any files
tingtinghsu@Hui-TingdeMacBook-Air git-rebase % git add cat1.html cat2.html
tingtinghsu@Hui-TingdeMacBook-Air git-rebase % git commit -m "cat1 cat2"
[detached HEAD aeff088] cat1 cat2
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 cat1.html
create mode 100644 cat2.html
tingtinghsu@Hui-TingdeMacBook-Air git-rebase % git add cat3.html cat4.html
tingtinghsu@Hui-TingdeMacBook-Air git-rebase % git commit -m "add cat3 cat4"
[detached HEAD dce6353] add cat3 cat4
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 cat3.html
create mode 100644 cat4.html
tingtinghsu@Hui-TingdeMacBook-Air git-rebase % git rebase --continue
Successfully rebased and updated refs/heads/master.
```
成功把整包的貓拆成兩個`cat1 cat2`, `cat 3 cat4`兩個檔案!

問題:
source tree如何install command line?

然後直接在command line叫出source tree `stree .`
# 在GitHub建立新專案
New repository,網頁版右上角 `+`
## 全新專案
```
…or create a new repository on the command line
echo "# gitfile" >> README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin https://github.com/tingtinghsu/gitfile.git
git push -u origin master
```
選擇`https`,`https://github.com/tingtinghsu/gitfile.git`
在推送的過程中會需要輸入帳號密碼
選擇`SSH` ,本地檔案會存一份公鑰和私鑰(不要在公用電腦上做)
## git push origin master的解釋
```
Git push origin master
把master的進度推一份到origin
Git push origin master
Git push abc master
Git push xyz master
Git push heroku master
Git remote add heroku git@heroku.com:tingtinghsu
Git push piano master (把貓推到鋼琴上)
```
`git push origin master`其實是縮寫
```
git push origin master
=>
git push origin master:master (遠端建立master branch的意思)
所以
git push origin master:cat (遠端建立cat branch的意思)
```
會用到`git push origin master:cat`的情境
```
git push heroku master
(heroku只能接受推master)
git push heroku dev
git push heroku dev:master
(dev推上heroku遠端節點,再把遠端推成master branch的意思)
```
練習:
```
git push origin master:cat
Total 0 (delta 0), reused 0 (delta 0)
remote:
remote: Create a pull request for 'cat' on GitHub by visiting:
remote: https://github.com/tingtinghsu/gitfile/pull/new/cat
remote:
To github.com:tingtinghsu/gitfile.git
* [new branch] master -> cat
```
## 在本地電腦產生SSH Key
```
ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/tingtinghsu/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/tingtinghsu/.ssh/id_rsa.
Your public key has been saved in /Users/tingtinghsu/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:Iq4xYSKyLdY27bThg4cZM+RZTPb+BhYj9TOT8jbLl2s tingtinghsu@Hui-TingdeMacBook-Air.local
The key's randomart image is:
+---[RSA 3072]----+
| |
| o . |
| + o . . |
| . + = * |
|+ = + + S + |
|o=.O.. = + |
|o.++O+. = o . |
|...B=oo = E |
| . .+. . o.. |
+----[SHA256]-----+
~ cd /Users/tingtinghsu/
~ ls
Applications Documents Dropbox Movies Pictures
Desktop Downloads Library Music Public
~/.ssh
~/.ssh ls
id_rsa id_rsa.pub known_hosts
~/.ssh code .
~/.ssh cat id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVr2bi2kTesH5q1qbs0kx2rlWjCV5poV87HI5d8J0WQXXEt5oRCEi3+TP1UklablEGTD2zRjIBLkzN7AIZadALzkFMdfyLT7Y8b1ll5kDc3lNyb6mCHfqjUe5XAWit2oVUS1zqaCbcBdRUvEmxR0vprO3ksaCPbHbYDkaK7lkq/rPgfGwMXVz1FHjj7vD4x7v1NcQnAyw0ZyGgV9/VeYs7eCILHdRXpAbstmFDyXcHYJwVgnRbEh0B4cCJ4/489sVsucZNgH/FghAOYAdX864I0OtNu44xBGyafauU2hOFgkxcRaio4Y09eUUD8IoEDmErShL/QT64ZJnxdG3sfswik3TvKuQWmbWn4CKN9Vxx0+1esg9dUgY7wjfDvhPgssEDmLp5ZLDy1PLhNf7uflSWmzwhrfa9XmNPW+X8ijpHwJSmfaKDvPaB78yNg9O3avjV6IMJW7FaV1tqqQyp9XLDpOnH180KMTNZjV68yUE+Jd11n6IJR0xy8J8WK04XkfE= tingtinghsu@Hui-TingdeMacBook-Air.local
```
## 為GitHub設定SSH
1. 確定該資料夾是否有設定遠端:
`git remote -v`
```
fatal: not a git repository (or any of the parent directories): .git
(要選擇有.git檔案的資料夾才可推)
```
2. 移除設定推送的遠端位置:
`git remote rm origin`
3. `-u` 設定預設的本地與推送的遠端位置配對
(通常最近手邊在忙的專案)
`git push -u origin master`
註:如果沒有`-u`,每次`git push`會出現
`The current branch master has no upstream branch.`
```
git push origin master
The authenticity of host 'github.com (140.82.114.3)' can't be established.
RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'github.com,140.82.114.3' (RSA) to the list of known hosts.
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 4 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (9/9), 899 bytes | 299.00 KiB/s, done.
Total 9 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), done.
To github.com:tingtinghsu/gitfile.git
* [new branch] master -> master
git push
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream origin master
```
# 從GitHub把檔案pull下來
`git fetch` 抓線上有的、但是本機沒有的檔案
```
~/Documents/projects/gitdemo master git fetch
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From github.com:tingtinghsu/gitfile
2ad4ead..5f08c95 master -> origin/master
```

`git merge origin master` 把本機的檔案跟上進度
```
~/Documents/projects/gitdemo master git merge origin/master
Updating 2ad4ead..5f08c95
Fast-forward
origin.html | 1 +
1 file changed, 1 insertion(+)
create mode 100644 origin.html
```
## git pull
`git pull` = `git fetch` + `git merge`
```
~/Documents/projects/gitdemo master git pull origin master
From github.com:tingtinghsu/gitfile
* branch master -> FETCH_HEAD
Updating 5f08c95..a5feaf1
Fast-forward
"\bpull.html" | 1 +
1 file changed, 1 insertion(+)
create mode 100644 "\pull.html"
```
## git clone `git網址`
eg. 加入新專案、加入新團隊
在什麼都沒有的情況下,沒辦法fetch
必須先直接把整包下載下來
fetch是用來補上進度
# 一起合作專案的時候
策略一:先拉下來一份,再merge,然後再推上去
=> 但這樣會分支圖很醜
策略二:每個人建立新分支,在分支上做事情
注意:
`git push -f`使用前要先告訴同事!
因為其他同事之後還要先砍掉原有檔案再`git clone`
(因為歷史紀錄已經改變)
## Pull Request
先fork其他人的專案到我自己的地方來
做完修改後再送PR
## merge策略
1. `create a merge commit`
Y型合併,多一次commit(如果發PR的人落後orgin/master的專案進度,commit數還會再增加)
2. `squash and merge`
一次送了多個commit在同一個PR,但擠壓完只有增加一次commit
3. `rebase and merge`
直接加上發PR的人送的commit數
## 自己fork的專案落後原作專案的commit進度,如何跟上?
=> 想辦法同步
[手冊:Syncing a fork](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/syncing-a-fork)
[怎麼跟上當初 fork 專案的進度?](https://gitbook.tw/chapters/github/syncing-a-fork.html)
```
# 新加上原作的remote master (名稱為upstream)
git remote add upstream https://github.com/kaochenlong/dummy-git.git
# 拉一份下來,再合併 (讓本機master往前移動)
git pull upstream master
```
# Git的世界觀
1. git的物件有計算公式
加密演算法:可以拿來驗證,但無法反推
只要內容不變,數值就不變
一樣的內容(就算都是空的內容),數值不變
mkdir不會產生亂數
**但是!commit本身的內容幾乎等於亂數**
2. git不在乎檔名是什麼,只在乎檔案內容的變化
`cat index.html | grep title`
`|` 的意思:把前面的東西丟給`|`的後面
`cat index.html | git hash-object --stdin`
會算出一個SHA1的一長串數值
git add (內容壓縮後,存在物件區)
```
git cat-file -t 看型態
git cat-file -p 看內容
```
## 切換branch時發生什麼事?
葡萄梗:從整串抽出來分支看
## Git不是做差異備份!
git
即使只改一個字,都重新計算,產生一顆物件