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