---
# System prepended metadata

title: 實用 Git Commands

---

# 實用 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 
