Git command note

版本控管功能多是好事,但指令多就容易出錯,避免悲劇發生,指令小抄保平安!
.ignore 各種語言 & framework範本
https://github.com/github/gitignore

SSH Keys (link)

符號

  • HEAD^^ #HEAD前一代的前一代
  • HEAD~2 #同 ^^,HEAD 前二代
  • HEAD~5..HEAD~2
  • HEAD~5...HEAD~2
  • HEAD@{3} #HEAD的異動編號,使用 git reflog 查看

設定

  • .gitconfig 路徑
    • Mac/Linux
      • System(底層):/usr/local/git/etc/gitconfig
        • 查詢:git config --show-origin --get credential.helper
      • Global(使用者): ~/.gitconfig
      • Local(專案): ./git/config
    • windows
      • C:\users\[user]\.gitconfig
  • 查詢完整設定
    • git config --list
  • 使用者名稱
    • git config --global user.name "First Last"
  • 電子郵件
    • git config --global user.email "[email protected]"
      • 套用到目前 commit
      • git commit --amend --reset-author
  • 指令縮寫
    • git config --global alias.[縮寫] [method]
  • 自動儲存帳號與密碼 
    • 永久
      • git config --global credential.helper store
    • 暫存 15 分鐘
      • git config --global credential.helper cache
    • 暫存 60 分鐘
      • git config credential.helper 'cache --timeout=3600'
    • 永久,用 Mac 鑰匙圈加密、存取
      • git config --global credential.helper osxkeychain
    • 解決 osxkeychain 一直要求帳密
      1. 在 finder 搜尋 Keychain Access,中文為「鑰匙圈存取」
      2. 在 app 搜尋 git repo 的 domain,注意「位置」,將對應的 key 刪除
      3. Pull 專案,會跳出輸入密碼,打 mac 登入時用的密碼

建立 repo

  • git init <dir>
      • 有 working directory
    • --bare
      • 無 working directory,純粹 .git 結構
    • --mirror
      • 無 working directory,純粹 .git 結構
      • 可以 base on 某個 repo,並使用 git fetch 與 base repo 同步

權限

  • init shared permissions
    • chgrp -R foo repodir                # set the group
    • chmod -R g+rw repodir               # allow the group to read/write
    • chmod g+s `find repodir -type d`    # new files get group id of directory
  • lock
    • repo 增加檔案 /hooks/update
    • #!/bin/sh
      # lock the myfeature branch for pushing
      refname="$1"
      
      if [[ $refname == "refs/heads/myfeature" ]]
      then
          echo "You cannot push to myfeature! It's locked"
          exit 1
      fi
      exit 0
      

新專案

  • 空資料夾
    $ git clone ./repo ./target_dir
  • 有資料
    $ git init
    $ git checkout -b master #可略
    $ git remote add origin repo_path
  • 推第一版
  • $ git push -u origin master


Repository操作

  • 更換專案的 repo Url
    • git remote set-url origin newUrl


branch操作

遠端

  • 新增
    • git push -u origin new_branch
  • 查詢
    • git branch -r
  • 刪除
    • git push origin :new_branch
  • 更名
    • git push -u origin old_branch:new_branch
    • 再刪掉 old_Branch
  • 修剪(refreash)
    • git remote prune origin  

本地

  • 新增/複製 分支
    • git checkout -b new_branch(新) origin/new_branch(來源)
  • 新增空白分支
    • git checkout -b --orphan <new_branch>
  • 查詢
    • git branch
  • 刪除
    • git branch -d
    • -D 強制刪除
  • 更名
    • git branch -m newBranch rename
    • -M 即使新名稱存在仍強制更名
  • 覆蓋遠端
    • git push remote  branch --force

checkout

  • branch
    • git checkout new_branch
    • git checkout new_branch origin/new_branch
  • 新增空白分支
    • git checkout -b --orphan <new_branch>
  • 切換失敗
    • git checkout -b branch origin/branch
  • 取自己分支修改前的檔案
    • git checkout -- *
  • 不切換,直接取其她分支檔案
    • git checkout branch commit filename
      • git checkout branch -- aa.php
  • 拉前一個版本的某個檔案
    • git checkout HEAD~1 -- path
    • 使用 reset --hard HEAD 還原
  • 退回前一版,且能再次 commit
    • git checkout HEAD~1 -- .

pull

  • git pull
    • 從 Remote 拉下來 merge,並產生新 commit "Merge branch 'master'..."
  • git pull --rebase
    • 可讓 tree 更乾淨
    • 比對 remote 新增的 commit,直接併入,不產生新的 Merge commit
    • 若有衝突,須每個 commit 一一排除
  • 將分支 commit 蓋回此線
    • git pull 來源repo 來源分支
      • ex.git pull origin master

diff

  • git diff HEAD filepath

clean

  • git clean -fdx #強力清除 untracked file
    • f=檔案, d=資料夾, X=忽略的檔案, x=忽略&非忽略的檔案

add

  • git add -A . #將 delete 的部分也加入清單
  • git add -u #只加 modify 檔案
  • git add filename
  • git reset HEAD filename #將某檔案從 add 清單中移除

commit

  • 交付
    • git commit -a -m "message" #交付全部,並寫入 commit 註解
  • 改註解
    • git commit --amend
      • 修改後 :wq! 儲存離開
  • 解除
    • git reset --soft HEAD~1 #刪除最近1期commit
      • 解除 commit,並將所有檔案回復到 git add 的狀態
  • 查未 push
    • git cherry -v #查詢未 push 的 commit
      • git log master ^origin/master #詳細
  • 查看檔案內容
    • show commitHash:filepath
  • 匯出檔案
    • show commitHash:filepath > filename
  • 複製其他分支 commit
    • git cherry-pick ab00d1
    • #情境:要上特定幾個 commit 到 online,可以將指定 n 個櫻桃(commit) 挑到 release 的 branch 中
  • 刪除遠端
    • git reset --hard <last_working_commit_id>
    • git push --force
    • # 小心別誤砍其他人的 code 

reset(重置)

  • git reset HEAD #放棄全部 add file ,或刪除指定 add file
  • git reset --soft HEAD #刪除 commit
  • git reset --soft HEAD~1 #解除 commit,並將所有檔案回復到 git add 的狀態
  • git reset --hard HEAD #放棄所有檔案變更
  • git reset --hard HEAD~1 #刪除 commit & 退回(rollback)到指定的前一版本
    • 若未 push,可用 git pull 還原
  • (link)

revert(恢復)

  • 與 reset 差異
    • 回復的內容,會新建立一個 commit
    • reset 在 merge 時,會被同 base 的 branch 填充重置掉的 commit?

mv(移動)

  • *移動檔案盡量使用此指令
  • git mv path new_path

rm

  • rm #shell 刪除文件
  • git rm --cached #刪除 git 追蹤文件
  • git rm #刪除 git 追蹤文件、並刪除文件
    • -f 強制, -r 資料夾遞迴

merge

  • 合併
    • git merge branch
      • --no-commit 
      • --squash #不會產生 commit
      • --no-ff
  • 取消合併
    • git reset --merge ORIG_HEAD
  • 出現Conflit,想取消合併
    • git reset --hard HEAD 
  • 解完 Conflit
    • 只需重新 add & commit

stash

  • git stash -a #將  add & delete 等異動檔案暫存
  • git stash list #列出 stash 清單
  • git stash apply #讀出指定 stash
  • git stash pop #讀出並刪除指定 stash
  • git stash drop stash@{1} #刪除指定 stash

log

  • git log -2 #顯示最近2個 commit
  • git log --name-only #只顯示 commit file list
  • git log origin/master..branch_name #看remote log
  • git log -stat
  • git log filepath #該檔案的所有 log
  • git log --grep pattern #查 message 符合 pattern 的 log 

reflog

  • git reflog brnach1 #顯示 branch1 歷史交付的紀錄

submodule

依附在主專案下,情境通常是 include 使用別人的專案使用,
每次 clone 專案,就需下 init、update submodule,
主專案會紀錄並「鎖定」submodule 版本,每次更新 submodule 務必 commit 版本號
  • 新增
  • $ git submodule add repo_addr [folder] 
        #會多出 .gitmodules,也會新增在 .git/config 中
    $ git status
        #       new file:   .gitmodules
        #       new file:   子模組folder
    $ git add .
    
  • 初始化
  • #方法一
    $ git clone repo_addr --recursive [folder] #直接把所有子模組拉下來,效果同方法二
    
    #方法二
    $ git submodule init #關聯到 .git/config 中,只需在專案初始時執行一次
    $ git submodule update --recursive
    $ git submodule status #看全部子模組版本
    
  • 更新
  • $ cd moduleFolder
    $ git pull
    
    #一次更新全部
    $ git submodule foreach --recursive git pull origin master
    
  • 更新子模組網址
  • $ nano .gitmodules #手動修改
    $ git submodule sync
    
  • 刪除
  • $ git submodule deinit -f moduleFolder #解除 .git/config 關聯
    $ git rm --cached moduleFolder
    $ rm -rf moduleFolder
    $ nano .gitmodules #手動移除該子模組
    
出現 No submodule mapping found,請看最下方「常見狀況」

檔案清單

  • git ls-files #全部檔案

顯示檔案內容

  • git show branch:filepath

archive

  • 包成壓縮檔
    • git archive -o patch.zip HEAD $(git diff --name-only [id])
  • export 檔案
    • git archive HEAD $(git diff --name-only [id]) | tar -x -C ./patch
    • git archive HEAD $(git diff HEAD~1 HEAD~2 --name-only) | tar -x -C 絕對路徑
      • ~1 為 base commit,目標的編號減 1,如果是目前的,就不用加 ~
      • ~2 為 target commit,要匯出的 commit 排序編號同 git log -2
      • 可以是大範圍,同個檔案,會以 base commit 為準,也就是會抓較近期的

rebase (link)

  • git rebase -i commit_id
    • commit_id 這次要編輯的範圍,起始 commit(舊)
    • 編輯器上到下為 舊->新 (與 log 相反)
    • 將 pick 改為 s(同squash) 可以合併掉該 commit 到舊一版 commit 中
  • git rebase -i HEAD~4
    • 合併最近4個 commit
  • git rebase --abort #取消
  • 解衝突
    • git add filename
    • git rebase --continue
  • *建議使用在 push 前整理分支用! 而用在 push 後容易出現令人沮喪的麻煩 

lock

  • .git/index.lock

.gitignore

  • 推薦 script
    • phpstorm
    • android
    • mac
    • ...
  • 編輯完後,執行 git clean 指令

[alias]

  • export file
    • git config --global alias.ex '!f() { mkdir -p $2;git archive HEAD $(git diff HEAD~$(($1-1)) HEAD~$1 --name-only) | tar -x -C $2;}; f'
    • 指令:git ex 版本數量 filepath
  • undo stash
    • git config --global alias.stash-unapply '!git stash show -p $1 | git apply -R'
  • 還原變更&清除
    • git cls --global alias.cls '!git reset --hard HEAD;git clean -f"


    File status lifecycle (圖片來自 link)

Git server (ubuntu)

  • 權限控管 Gitolite
  • GitWeb
  • 使用 nginx htpasswd
    • linux下指令 htpasswd /etc/nginx/.htpasswd <username>

開發流程

  • Github Flow
    1. Create A Branch (建立一個分支)
    2. Add Commits (新增 Commits)
    3. Open a Pull Request (開一個推送請求PR)
    4. Discuss And Review (討論及審查)
    5. Deploy (部署)
    6. Merge (合併)
  • Gitlab Flow
    • 中文說明
    • upstream first policy
    • git cherry-pick 機制
      • git merge --no-ff 或 git merge --squash
  • Git Flow
    • 版控基本規劃(過去實行筆記)
      • 一個 project 一個 repo
      • 環境 branch
        • master - 上線版
        • dev - 開發版
        • beta - 測試版
        • stage - 上線前版

        • DEV - 開發環境
        • SIT - 系統整合測試
        • UAT - 使用者(業主)驗收測試
        • PEM - 性能評估測試(壓測)
        • SIM - 仿真
        • 事件 branch
          • pj_xxx - project 中的某個獨立小專案
          • hotfix_xxx - 上線後有問題,當日需修復的 bug
          • regular_xxx - 程式碼重構,非急迫性質
          • feature_xxx - 小功能
          • workflow
            • leader 建立 repo、環境 branch
            • Senior 將 base code Commit 到 dev
            • 小組從 dev 再各自開 feature_xx
            • 小組完成後,Merge 回 dev並測試
            • dev 環境測試有問題,則修正該 pj_xx,完成後重新 Merge 一次
            • 上 beta 環境,依照小 feature_xx 的相依程度,分開或同時上
            • beta 環境測試有問題,改完再從 dev 開始測
            • stage 同理,並非 merge 整個 beta,而是個別 merge feature branch
            • 若該階段所有小 pj 完成,則 master 直接 merge stage
            • 上線後有問題,開 hotfix,從 dev 向上測,但優先度高



      如何在已經存在的 project 套用 repo

      $ cd 專案目錄內
      $ git init
      $ git add .
      $ git commit -m "base version"
      $ git remote add origin repo網址
      $ git push -u origin master
      
      1. 切分支
      $ git checkout -b dev
      $ git push -u origin dev
      

      在 GitHub 上 Fork 的專案,如何定期更新

      1. 一開始幾種方式變成自己的 code
        1. github 上直接 Fork 成為自己的 project
        2. 或用 clone,再改寫 remote origin
        3. 或建一個 repo,再做以下動作
      2. 概念
        1. 2個 remote,一個是 origin(自己 fork下來的),另一個是 upstream(原生專案更新用)
        2. 更新 upstream 後,合併回 origin
      3. 相關資料
        1. Forking a Github repo to Bitbucket (link)
      4. 操作
        1. 建立
        2. $ git #先 init 或 clone origin 專案
          $ echo " " > README.md
          $ git add .; git commit -m "README.md"
          $ git remote add upstream https://github.com/fork來源作者/fork來源專案名稱
          $ git pull upstream #後面可帶指定 branch
              $ git merge upstream/分支名稱 --squash #merge 不產生其他 commit
              或
              $ git rebase upstream/master  #將 remote 新 commit 貼到 local,並產生 n 個 cherry
          $ git #可考慮用 rebase 合併,參考下方維護
          $ git push -u origin master
          
        3. 日常維護
        4. $ git pull upstream
          $ #git reset --hard HEAD #放棄未 commit 的所有資料
          $ git merge upstream/分支名稱 --squash #merge 不產生其他 commit
          $ #排除衝突 using 'Theirs'
          $ git push
          
        5. 刪除上游
        6. $ vi .git/config
          $ #刪除 upstream
          

      將 local 專案(含所有分支)轉到 bitbucket

      $ cd 已存在的專案folder
      $ git remote add bitbucket bitbucket專案網址 #增加一個remote 
      $ git push --all bitbucket #將全部分支推上去
      $ git push --tags bitbucket #將全部tag推上去
      
      *.可直接在 bitbucket 使用 import repository,輸入 old project & auth 即可

      完整轉移 Repository

      $ git clone --mirror [email protected]:myteam/myrepo.git
      $ cd myrepo
      $ git remote set-url --push origin [email protected]:newteam/myrepo.git
      $ git push --mirror
      

      Merge 出錯,如何還原?

      1. 通常是 merge 時有問題,將 merge 前的版本打包出來
      常見狀況
      • shell script 出現 no found (參考)
        1. 先檢查文件 Line Separator,是 CRLF(windows) or CR(MAC)
        2. 使用 git config core.autocrlf ,看是否回傳 true
        3. 如果你專案都是 CRLF,那就設為 false,若不是則設 true
        4. 刪除專案,若只對此專案修改,請保留 .git,其他 folder 清掉
        5. #三選一
          $ git config --system core.autocrlf true #對全系統
          $ git config --global core.autocrlf true #對此user
          $ git config core.autocrlf true #對此專案
          
        6. 重新 pull 或 clone 資料
      • No submodule mapping found in .gitmodules for path 'path/myFolder'
        • 使用 git rm --cached path/myFolder

      推薦文章



      git merge 與 rebase 的觀念與實務應用
      https://www.slideshare.net/WillHuangTW/git-merge-rebase
      Git command note Git command note Reviewed by Wild on 7/15/2015 05:39:00 下午 Rating: 5

      沒有留言:

      沒有Google帳號也可發表意見唷!

      技術提供:Blogger.