# 實用 Git Commands
<!-- ## 基本招
1. git init
3. git add .
4. git commit -m "(message)"
5. git push origin (branch)
6. Ctrl+L 清空git version control視窗
-->
<!--
## 自動加入commit message 前贅詞
add the current date to your commit message in Visual Studio Code.
1. Open the terminal.
2. Navigate to your Git repository's root directory using the `cd` command. For example, if your repository is located at `/Users/username/my_project`, you would type:
```bash
cd /Users/username/my_project
```
3.
```bash
cd .git/hooks
```
4. In the `.git/hooks` directory, create a new file called `prepare-commit-msg`. You can use a command like this:
```bash
touch prepare-commit-msg
```
5. Open the `prepare-commit-msg` file in a text editor and add the following script:
```bash
code prepare-commit-msg
```
```bash
#!/bin/sh
DATE=`date +%Y.%m.%d`
echo "$DATE,$(cat $1)" > $1
```
6. Save and close the file.
7. Finally, make the `prepare-commit-msg` file executable ( whenver first create this file) by running the following command:
```bash
chmod +x prepare-commit-msg
```
Please note that this setup applies only to the current Git repository. If you want to apply this setup to all new Git repositories, you can set up a global `prepare-commit-msg` hook.
**if you need to cancel it**
```bash
code prepare-commit-msg
```
and only keep
```bash
#!/bin/sh
```
OR
您也可以直接刪除 prepare-commit-msg 文件。您可以使用以下命令來刪除它:
```bash
rm .git/hooks/prepare-commit-msg
```
## precommit-script
```bash
#!/bin/sh
# Add date to commit if no date found
DATE=`date +%Y.%m.%d`
if ! grep -q "$DATE" "$1"; then
echo "$DATE,$(cat $1)" > $1
fi
# Check for !test keyword
if git diff --cached --unified=0 | grep "^\+\s*.*!test"
then
echo "Found !test keyword in the new changes. Terminating commit."
exit 1
fi
# prevent pushing to main branch
```
自動跑單元測試
```bash
# Check if test script exists in package.json
if grep -q "\"test\"" package.json
then
# Run tests
npm run test || {
echo "Tests failed. Terminating commit."
exit 1
}
fi
```
-->
<!-- ## 簡化git commits
- 把多個小功能commits 集合(squach)成一個commit https://docs.github.com/en/desktop/managing-commits/squashing-commits-in-github-desktop -->
## 遠端Repo
1. 第一次新增git remote add origin (url)
事後修改orgin的話用 git remote set-url origin (url)
1. git push -u origin main (預設origin設好之後只要用git push就好)
<!-- - 避免Pull Request 刪除檔案
- To prevent Git from deleting files when you use git pull, you can add the --no-rebase option to the command:
`git pull --no-rebase origin main`
This will tell Git to update your local repository from the remote repository, but without performing a rebase, which is the operation that can cause files to be deleted. Instead, Git will perform a merge, which will preserve any files that are not present in the remote repository. -->
<!-- - 不顯示Untracked files
- If you simply don't want to see them when committing in any repo, set the Git config variable status.showUntrackedFiles to no, as noted here: ` git config --global status.showUntrackedFiles no`
-->
- 回到上一個Commited version
- `git checkout (version)
- Undo Commit
- git revert (commit)
- 從remote repo獲取最新版本
- git pull:這作法會合併remote repo資料合併進working dir
## Branching
- 建立分支
- 創建新分支 `git branch new-branch`
切換分支 `git checkout -b new-branch`
- 刪除分支
- 删除本地master:
git branch -d master
- 更新遠端Repo
git push origin --delete (branch)
- 暫存工作環境的修改
- git stash:將當前工作環境的修改暫存起來,以便切換分支。工作上會用到
- 比較分支差異
- git diff:比較working dir中的文件與暫存區或local repo的差異。
## Merge
### 從開發分支merge到對外上線的branch有衝突,如何在IDE解決把"staging"換成開發的分支、"master"換成對外上線的分支
1. git checkout "staging"
git fetch origin
2. git checkout "master"
git fetch origin
git merge --no-ff "staging"
3. 解完衝突後
git push origin "master"
### 只merge部分檔案
- 若確定有哪些commit要merge, 依照commit hash使用cherry pick
- 若確定有哪些檔案要merge, 指定該檔案的所有commit
git checkout staging -- src/router/index.js
## Git Squash:
### 方法1:使用 `git merge --squash` 與臨時分支進行合併
1. **建立並切換到一個基於 `master` 的新分支**
- 建立一個名為 `work` 的新分支,基於 `master`(或合適的基礎分支)。
```bash
git checkout -b work master
```
*(這會建立一個名為 `work` 的新分支並切換到該分支)*
2. **將功能分支的變更合併進來**
- 使用 `git merge --squash` 將 `my_feature` 分支的所有變更帶入。
```bash
git merge --squash my_feature
```
*(此指令會將 `my_feature` 分支的所有變更整合起來並準備提交,但不會建立任何提交紀錄)*
3. **提交 Squash 後的變更**
- 以適當的訊息新增一個提交,代表合併後的變更。
```bash
git commit -m "我的 Squash 提交訊息"
```
*(此時,`work` 分支應該與 `my_feature` 分支內容相同,但只會包含一個基於 `master` 的提交紀錄)*
4. **返回功能分支並重置**
- 切換回 `my_feature` 分支並重置為 `work` 分支的 Squash 狀態。
```bash
git checkout my_feature
git reset --hard work
```
5. **更新 Pull Request**
- 強制推送變更。
```bash
git push -f
```
6. **清理臨時分支**
- 刪除 `work` 分支以清理臨時分支。
```bash
git branch -D work
```
## 偶發問題
* 在一個commit不小心刪了一個function但那個commit在幾週前
- 在所有檔案以function名稱查找
- `git log -S'myFunction'`
- 在特定檔案找
- `git log -S'myFunction' -- path/to/file`
<!-- * 清除過去不小心track到的git 紀錄,讓gitignore重新套用, git rm -r --cached (檔案或資料夾) 若是針對node_modules 可以重開IDE就好
* 刪除父層的舊git history
* git rev-parse --show-toplevel
* rm -rf .git (只在git bash有用)
* 回到自己的repo,乾淨不受影響了
-->
## 查找並切換這個檔案所有的編修紀錄
- 啟用gitlens
- vscode 右上角 ... find changes with prev / next revision