git
首先是推薦文章內的重點:好的 commit message 的七個規則
The seven rules of a great Git commit message
這樣可以在使用 $ git log 閱讀時叫容易分辨出哪行是標題
因為標題字數超過 50 在 github 上會被隱藏到 … 裡面
需要額外點開才能完整知道這個 commit 在做什麼
超過 50 字可能就不是一個精簡的標題了
Capitalize the subject line
標題首字大寫
Do not end the subject line with a period
標題結尾不要句點
Use the imperative mood in the subject line
標題用命令口吻
Wrap the body at 72 characters
內文一行字數不超過 72
這樣在 $ git log 裡面看會比較清楚,排版比較好看
因為看 commit 的人是想知道你為什麼要做這件事,而不是要知道你如何做這件事的
ref from:
how to write git message
git blame [file]查看該file適合人在何時修改的
-L [start,end]:限制範圍在該file的第幾行到第幾行
-C :找出原始程式碼的出處
git flow init
新功能的開發是由 'develop' 分支的最後一個版本發展出來的
git flow feature start [branch name]
完成新功能
當你在新功能分支完成新功能後,使用下列指令來結束新功能開發:
git flow feature finish [branch name]
這個指令會替你完成下列動作:
發佈新功能分支
讓遠端其他人也可使用這個分支
git flow feature publish [branch name]
取得新功能分支
取得遠端上的新分支
git flow feature pull [branch name]
追蹤遠端上的分支
git flow feature track [branch name]
使用下列指令準備推出(release)新版本分支:
git flow release start RELEASE [BASE]
完成推出新版本
完成 release 版本是一個很大的 git 分支操作。但你只許要執行下列指令:
git flow release finish RELEASE
git flow 會幫你執行下面幾個步驟:
開始快速修復
git flow hotfix start VERSION [BASENAME]
你必須填寫一個 VERSION 參數,這代表當你完成 hotfix 時發佈的版本號碼。
此外你可以自由挑選修復開始的分支名稱**[BASENAME]**
,分支名稱如果不填寫的狀況下,預設是 'master'。
完成快速修復
git flow hotfix finish VERSION
git reflog
來查看 HEAD
的修改紀錄git log -g
查看 reflog 的詳細內容比較 **git reset HEAD^**
的參數
指令
效果
git reset HEAD^
回到前一個 patch,且恢復檔案的狀態
git reset --soft HEAD^
回到前一個 patch,但保持檔案狀態為 Changes to be committed
git reset --mixed
回到前一個patch,狀態為unstage
git reset --hard HEAD^
回到前一個 patch,且強制清除檔案的修改內容
always discards the index (staged changes);
aborts if unstaged and staged changes present on any file
keeps, but unstages, the index;
aborts if the reset target touches the same file
簡單來說--keep
只要有修改到相同檔案部份,reset就會abort,但是--merge
只有在修改要reset的檔案或是新增要reset時沒有的檔案,殘會abort,--merege
域社會清除所有在index中的檔案,需要特別注意,而--keep
會將期轉為unstage。
https://stackoverflow.com/questions/24728543/git-reset-merge-vs-git-reset-keep
因為凡事只要做了 commit 的動作,git 就會重新產生一組新的 commit id
而 git commit –amend 後面也可以加 -m 的參數帶入新的 commit message
$ git commit --amend -m <title> # 只要提交 title
$ git commit --amend -m <title> -m <message> # 提交 title 以及 message
$ git commit --amend -m <title> -m <msg1> -m <msg2> .... # 提交多段 messages
若不小心和上一個patch合併3則可利用下指令將兩者分離
git reset –soft HEAD@{1}
git cherry-pick <commit id>
挑入 patchhttps://zlargon.gitbooks.io/git-tutorial/content/patch/remove.html
git revert <commit id>
還原指定的 patchgit revert --continue
告知 git 已經解完衝突git revert --abort
來要放棄這次 revertgit add -p
提交檔案部分的內容git checkout -p
回復檔案部分的內容git format-patch -n
or
git format-patch <commit> 從某一個 commit 開始往後生成patch
git format-patch -n <commit> 從某一個 commit 開始從前先成 n 個patch
打包最新的三個 commit
git format-patch -3
git apply --check patch #套用patch時確認能否直接套用
git am xxx.patch
git diff > patch-issue-1.patch
git add newfile
git diff –staged > patch-issue-2.patch
git add newfile
git diff HEAD > patch-issue-2.patch
git format-patch COMMIT_ID
git format-patch HEAD~2
git format-patch origin/master
git format-patch –binary –full-index origin/master
git checkout --track(-t) origin/serverfix
git push [遠程名] :[分支名]
git push origin :serverfix
git push origin --delete [branch]
ls | xargs -P10 -I{} git -C {} pull
Lists commit objects in reverse chronological order
$git checkout `git rev-list -1 --before="$DATE" master`
Note: checking out '79ad22cfb7d1ea950f4ffa2860f63bd4d0f31692'.
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 performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b <new-branch-name>
HEAD is now at 79ad22c... Need to update validate_sync with new column
效果等同於
$ DATE='Sep 3 2014'
$ git rev-list -1 --before="$DATE" master | xargs -Iz git checkout z
# 找出所有git object中,data<Sep 3 2014的onject,只取最接近現在的一個,然後checkout至該object。
之後就可以對該節點進行操做
$ git checkout `git rev-list -1 --before="$DATE" master`
## 用一個tag標注,方便以後checkout
$ git tag bug_23142
## go back master
$ git checkout master
## go to the mark tag
$ git checkout bug_23142
## 也可以直接建立一個新的branch
$ git co -b "bug23142"
利用file size尋找
$ SIZE=167092
$ git rev-list --all \
| while read commit
do if git ls-tree -l -r $commit \
| grep -q -w $SIZE
then echo $commit
break
fi
done
d91807d59a6326e48077311e96e4d5730f24304c
Finding a git commit by error message
git log --format=%h \
| xargs -n 1 -I sh -c \
"echo -n {}; git show {}:bucardo | head -8627 | tail -1" \
| less
## About 35 lines down:
379c9006 $dbh = DBI->connect($BDSN, 'bucardo'...
git remote -v
git remote set-url origin http//github.com/repo.git
git diff-tree --no-commit-id --name-only -r
COMMIT_ID
or
git show --pretty="format:" --name-only COMMIT_ID
source: http://stackoverflow.com/a/424142/1391963
git diff --cached origin/master
git cherry -v master
(master is the branch you want to compare)
git clean -f
Including directories:
git clean -f -d
Preventing sudden cardiac arrest:
git clean -n -f -d
Source: http://stackoverflow.com/q/61212/1391963
rebase is like merge,but it will merge your branch after the specific branch.
將整個feature branch移動到master branch之後
git co feature
git rebase master
可以指定要被merge的commit
讓user可以edit list before rebasing.
git checkout feature
git rebase -i master
1 pick c01b36d hello commit
2 pick 30fcc2a commit test
3 pick d15923d test2
4 pick 8cd6a3f test3
5
6 # Rebase 9d960fb..8cd6a3f onto 9d960fb (4 command(s))
7 #
8 # Commands:
9 # p, pick = use commit
10 # r, reword = use commit, but edit the commit message
11 # e, edit = use commit, but stop for amending
12 # s, squash = use commit, but meld into previous commit
13 # f, fixup = like "squash", but discard this commit's log message
14 # x, exec = run command (the rest of the line) using shell
15 # d, drop = remove commit
16 #
17 # These lines can be re-ordered; they are executed from top to bottom.
18 #
19 # If you remove a line here THAT COMMIT WILL BE LOST.
20 #
21 # However, if you remove everything, the rebase will be aborted.
22 #
23 # Note that empty commits are commented out
絕對不要在公用的branch 上使用rebase
如果沒有把握,可以先創立一個暫時的rebase分支,確認沒問題後才merge回主要分支
git checkout feature
git checkout -b temporary-branch
git rebase -i master
# [清理目录]
git checkout master
git merge temporary-branch
可以參考 https://blog.yorkxin.org/2011/07/29/git-rebase
git bisect start
git bisect bad
git bisect good <some tag or rev that knew was working>
git bisect run [unittest runner of choice]
git bisect reset # to exit and put code back to state before git bisect start
git clone xxx
cd mcplugins
git checkout origni/master -b mylib
git filter-branch --prune-empty --subdirectory-filter plugins/mylib mylib
git push xxx/mylib.git mylib:master
git merge y
# CONFLICT ...
git checkout --theirs conflict.txt # conflict.txt is the conflict file
git add conflict.txt
git commit
N.b. the function is there as hack to get $@ doing
what you would expect it to as a shell user.
Add the below to your .gitconfig for easy ours/theirs aliases.
ours = "!f() { git checkout –ours $@ && git add $@; }; f"
theirs = "!f() { git checkout –theirs $@ && git add $@; }; f"
git merge-base找出兩分之開始分叉的base
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch [PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA]' \
--prune-empty --tag-name-filter cat -- --all
echo "YOUR-FILE-WITH-SENSITIVE-DATA" >> .gitignore
$ git add .gitignore
$ git commit -m "Add YOUR-FILE-WITH-SENSITIVE-DATA to .gitignore"
git push origin --force --all
merge
, any branches they created off of your old (tainted) repository history. One merge commit could reintroduce some or all of the tainted history that you just went to the trouble of purging.git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --prune=now
假設我們的版控歷史紀錄如下:
R–A–B–C–D–E–HEAD
接下來要移除 B 跟 C 的 commit tree,變成
R–A–D’–E–HEAD
依序執行下列指令可以移除 B & C
# detach head and move to D commit
git checkout <SHA-for-D>
# move HEAD to A, but leave the index and working tree as for D
git reset --soft <SHA-for-A>
# Redo the D commit re-using the commit message, but now on top of A
git commit -C <SHA-for-D>
# Re-apply everything from the old D onwards onto this new place
git rebase --onto HEAD <SHA-for-D> master
# push it
git push --force
or use cherry-pick
git rebase --hard a
git cherry-pick d
git cherry-pick e
git config --global core.editor vim
git config --list
git config <key>
git source tree
git submodule add <repo>
git submodule init
git submodule update
git submodule foreach git pull origin master
Clone all submodules
git clone --recursive git://xxxx
git submodule update --init --recursive
Remove submodule
Creating a submodule is pretty straight-forward, but deleting them less so. The commands you need are:
$ git submodule deinit submodulename
$ git rm submodulename
$ git rm --cached submodulename
$ rm -rf .git/modules/submodulename
git submodule foreach git reset --hard
git submodule foreach --recursive git reset --hard
git hook help
https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
git filter-branch
git fetch origin pull/ID/head:BRANCHNAME
and
git checkout BRANCHNAME
If the PR code changes and you want to update:
# Do this while in the pr37 branch
$ git pull upstream pull/37/head
You'll only do this the first time – it creates the local upstream_master branch, tracks it to upstream_master, and switches to the branch:
$ git checkout -t -b upstream_master upstream/master
After the first time you'll just do:
$ git checkout upstream_master
Now merge the PR:
$ git merge pr37
NOTE: You should edit the merge commit message to reference the PR (using, say #37 in it).
Now push:
$ git push upstream HEAD:master
eg:A->B->C->D
更改B以後的commit的使用者
git filter-branch --env-filter '
WRONG_EMAIL="wrong@example.com"
NEW_NAME="New Name Value"
NEW_EMAIL="correct@example.com"
if [ "$GIT_COMMITTER_EMAIL" = "$WRONG_EMAIL" ]
then
export GIT_COMMITTER_NAME="$NEW_NAME"
export GIT_COMMITTER_EMAIL="$NEW_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$WRONG_EMAIL" ]
then
export GIT_AUTHOR_NAME="$NEW_NAME"
export GIT_AUTHOR_EMAIL="$NEW_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags
git config user.name "YOUR NAME"
git config user.email "YOUR EMAIL"
--source
:顯示在命令行上給出的每次引用的引用名稱--all
:start from every branchreverse
:prints in reverse ordergit log --author="name or email"
git log --committer="name or email"
git log -- <path to file>
git log -- **/*.js
git log --name-status -- **/*.js
git log -L :FunctionName:FilePath
git tag --contains <commitid>
$ git checkout <branch-you-want-the-directory-from> -- <folder-name or file-name>
First find the commit when the file last existed:
$ git rev-list -n 1 HEAD -- filename
Then checkout that file:
git checkout deletingcommitid^ -- filename
$ git tag -d <tag_name>
$ git push <remote> :refs/tags/<tag_name>
$ git archive --format zip --output /full/path/to/zipfile.zip master
(master)$ git mv --force myfile MyFile
(master)$ git fetch --all
(master)$ git reset --hard origin/master
(master)$ git rm --cached log.txt
Assuming the hash of the commit you want is c5f567:
(master)$ git checkout c5f567 -- file1/to/restore file2/to/restore
If you want to revert to changes made just 1 commit before c5f567, pass the commit hash as c5f567~1:
(master)$ git checkout c5f567~1 -- file1/to/restore file2/to/restore
Assuming you want to compare last commit with file from commit c5f567:
$ git diff HEAD:path_to_file/file c5f567:path_to_file/file
Same goes for branches:
$ git diff master:path_to_file/file staging:path_to_file/file
This works great for config templates or other files that require locally adding credentials that shouldn't be committed.
$ git update-index --assume-unchanged file-to-ignore
Note that this does not remove the file from source control - it is only ignored locally. To undo this and tell Git to notice changes again, this clears the ignore flag:
$ git update-index --no-assume-unchanged file-to-stop-ignoring
You might have a repository that requires authentication. In which case you can cache a username and password so you don't have to enter it on every push and pull. Credential helper can do this for you.
$ git config --global credential.helper cache
$ git config --global credential.helper 'cache --timeout=3600'
To find a credential helper:
$ git help -a | grep credential
# Shows you possible credential helpers
$ git config core.fileMode false
If you want to make this the default behaviour for logged-in users, then use:
$ git config --global core.fileMode false
Git 2.23:
shorter:
view commit files:
git checkout master # first get back to master
git checkout experiment -- app.js # then copy the version of app.js
# from branch "experiment"
Git 2.23: git switch/restore
git switch master
git restore -s experiment -- app.js
$ git push git@github.com:owner/repo.git HEAD:target-branch
git fetch origin pull/ID/head:BRANCHNAME