Reference
- This is good: http://blog.igevin.info/posts/git-cheat-sheet/
Some random stuff
在 GitHub 上 fork 到自己的倉庫壹店,如 docker_user/docker_practice赘来,然后 clone 到本地番电,并設(shè)置用戶信息臣缀。
$ git clone git@github.com:docker_user/docker_practice.git
$ cd docker_practice
$ git config user.name "yourname"
$ git config user.email "your email"修改代碼后提交褐奴,并推送到自己的倉庫。
$ #do some change on the content
$ git commit -am "Fix issue #1: change helo to hello"
$ git push在 GitHub 網(wǎng)站上提交 pull request阳啥。
定期使用項(xiàng)目倉庫內(nèi)容更新自己倉庫內(nèi)容床牧。
$ git remote add upstream https://github.com/yeasy/docker_practice
$ git fetch upstream
$ git checkout master
$ git rebase upstream/master
$ git push -f origin master
Merge branch
Simple Solution:
git checkout master
git pull origin master
git merge test
git push origin master
Upper operations have two issues:
More complicated Solution:
This is one very practice question, but all before answers are not practical.
Like
git checkout master
git pull origin master
git merge test
git push origin master
Upper operations have two issues:
it's not one safety way, cause we don't know is there any conflicts between test branch and master branch
it would "squeeze" all test commits into one merge commit on master, that is to say on master branch, we can't see the all change logs of test branch
So, when we suspect there would some conflicts, we can have following git operations:
git checkout test
git pull
git checkout master
git pull
git merge --no-ff --no-commit test
Test merge before commit, avoid a fast-forward commit by --no-ff,
If conflicts notified, we can run git status to check details about the conflicts and try to solve
git status
Once we solve the conflicts, or there is not any conflicts, we commit and push them
git commit -m 'merge test branch'
git push
But this way will lose the changes history logged in test branch, and it would make master branch to be hard for other developers to understand the history of the project.
So the best method is we have to use Rebase instead of Merge (suppose, when in this time, we have solved the branches conflicts).
Following is one simple sample, for advanced operations, please refer to http://git-scm.com/book/en/v2/Git-Branching-Rebasing
git checkout master
git pull
git checkout test
git pull
git rebase -i master
git checkout master
git merge test
Yeap, when you have uppers done, the Test branch's all commits will be moved onto the head of Master branch. The major benefit of rebasing is that you get a liner and much cleaner project history.
The only thing you need to avoid is: never use rebase on public branch, like master branch.
like following operation:
git checkout master
git rebase -i test
never do these operations.
Details for https://www.atlassian.com/git/tutorials/merging-vs-rebasing/the-golden-rule-of-rebasing
appendix:
if you are not sure the rebasing operations, please refer to: https://git-scm.com/book/en/v2/Git-Branching-Rebasing
Git ignore
# put this in the directory where you want git to ignore everything but the directory sturcture
# Ignore everything in this directory
*
# Except this file
!.gitignore
Git Flow
https://guides.github.com/introduction/flow/
Tutorial
Based on http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
Git on local machine
版本退回
- check log
git log
- git 使用
HEAD
表示當(dāng)前版本。HEAD^
HEAD^^
表示前一個侄榴,2個版本雹锣。
git reset --hard HEAD^
- can use
commit id
to placeHEAD
to a particular version
git reset --hard 3628164
git resest --hard commit_id
- can use
git reflog
to track all the command
git reflog
ea34578 HEAD@{0}: reset: moving to HEAD^
3628164 HEAD@{1}: commit: append GPL
ea34578 HEAD@{2}: commit: add distributed
cb926e7 HEAD@{3}: commit (initial): wrote a readme file
Working directory and Repository
工作區(qū)(Working Directory)
就是你在電腦里能看到的目錄,比如我的learngit文件夾就是一個工作區(qū)版本庫(Repository)
工作區(qū)有一個隱藏目錄.git癞蚕,這個不算工作區(qū)蕊爵,而是Git的版本庫。
Git的版本庫里存了很多東西涣达,其中最重要的就是稱為stage(或者叫index)的暫存區(qū)在辆,還有Git為我們自動創(chuàng)建的第一個分支master证薇,以及指向master的一個指針叫HEAD.
所以,git add命令實(shí)際上就是把要提交的所有修改放到暫存區(qū)(Stage)匆篓,然后浑度,執(zhí)行g(shù)it commit就可以一次性把暫存區(qū)的所有修改提交到分支。
一旦提交后鸦概,如果你又沒有對工作區(qū)做任何修改箩张,那么工作區(qū)就是“干凈”的:
$ git status# On branch masternothing to commit (working directory clean)
Note: git commit
will only commit changes that has been add into stage zone. The changes in working directory but not in stage zone will not be committed.
用git diff HEAD -- file_name 命令可以查看工作區(qū)和版本庫里面最新版本的區(qū)別
git diff HEAD -- readme.txt
撤銷修改
1. Discard the changes in working directory (unstaged)
git checkout -- file_name 可以丟棄工作區(qū)的修改
git checkout -- readme.txt
$ git status
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: readme.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
命令git checkout -- readme.txt意思就是,把readme.txt文件在工作區(qū)的修改全部撤銷窗市,這里有兩種情況:
一種是readme.txt自修改后還沒有被放到暫存區(qū)先慷,現(xiàn)在,撤銷修改就回到和版本庫一模一樣的狀態(tài)咨察;
一種是readme.txt已經(jīng)添加到暫存區(qū)后论熙,又作了修改,現(xiàn)在摄狱,撤銷修改就回到添加到暫存區(qū)后的狀態(tài)脓诡。
總之,就是讓這個文件回到最近一次git commit或git add時的狀態(tài)媒役。
2. Discard changes that already be staged
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: readme.txt
#
Git同樣告訴我們祝谚,用命令git reset HEAD file_name 可以把暫存區(qū)的修改撤銷掉(unstage),重新放回工作區(qū):
$ git reset HEAD readme.txt
$ git status
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: readme.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
After this, apply the same method to discard the changes in working directory.
$ git checkout -- readme.txt
$ git status
# On branch masternothing to commit (working directory clean)
Delete and recover file
** 1. delete file from repository**
$ rm test.txt
$ git rm test.txt
$ git commit -m "remove test.txt"
** 2. Recover deleted file **
另一種情況是刪錯了酣衷,因?yàn)榘姹編炖镞€有呢交惯,所以可以很輕松地把誤刪的文件恢復(fù)到最新版本:
$ git checkout -- test.txt
git checkout
其實(shí)是用版本庫里的版本替換工作區(qū)的版本,無論工作區(qū)是修改還是刪除穿仪,都可以“一鍵還原”席爽。
Remote Repository
After create a new repo on GitHub, we can connect this new Github repo with our local repo, and push content to it
$ git remote add origin git@server-name:path/repo-name.git
$ git remote add origin git@github.com:michaelliao/learngit.git
請千萬注意,把上面的michaelliao替換成你自己的GitHub賬戶名牡借,否則拳昌,你在本地關(guān)聯(lián)的就是我的遠(yuǎn)程庫,關(guān)聯(lián)沒有問題钠龙,但是你以后推送是推不上去的,因?yàn)槟愕腟SH Key公鑰不在我的賬戶列表中御铃。
添加后碴里,遠(yuǎn)程庫的名字就是origin,這是Git默認(rèn)的叫法上真,也可以改成別的咬腋,但是origin這個名字一看就知道是遠(yuǎn)程庫。
$ git push -u origin master
Counting objects: 19, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (19/19), done.
Writing objects: 100% (19/19), 13.73 KiB, done.
Total 23 (delta 6), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
* [new branch] master -> master
Branch master set up to track remote branch master from origin.
由于遠(yuǎn)程庫是空的睡互,我們第一次推送master分支時根竿,加上了-u參數(shù)陵像,Git不但會把本地的master分支內(nèi)容推送的遠(yuǎn)程新的master分支,還會把本地的master分支和遠(yuǎn)程的master分支關(guān)聯(lián)起來寇壳,在以后的推送或者拉取時就可以簡化命令醒颖。
從現(xiàn)在起,只要本地作了提交壳炎,就可以通過命令:
$ git push origin master
Branch Management
創(chuàng)建與合并分支
查看分支:git branch
創(chuàng)建分支:git branch <name>
切換分支:git checkout <name>
創(chuàng)建+切換分支:git checkout -b <name>
合并某分支到當(dāng)前分支:git merge <name>
刪除分支:git branch -d <name>
git merge命令用于合并指定分支到當(dāng)前分支泞歉。合并后,再查看readme.txt的內(nèi)容匿辩,就可以看到腰耙,和dev分支的最新提交是完全一樣的。
$ git merge dev
Updating d17efd8..fec145a
Fast-forward
readme.txt | 1 +
1 file changed, 1 insertion(+)
注意到上面的Fast-forward信息铲球,Git告訴我們挺庞,這次合并是“快進(jìn)模式”,也就是直接把master指向dev的當(dāng)前提交稼病,所以合并速度非衬痈螅快。
當(dāng)然溯饵,也不是每次合并都能Fast-forward侵俗,我們后面會講其他方式的合并。
合并完成后丰刊,就可以放心地刪除dev分支了.
準(zhǔn)備合并dev分支隘谣,請注意--no-ff參數(shù),表示禁用Fast forward:
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)
解決沖突
用帶參數(shù)的git log也可以看到分支的合并情況
$ git log --graph --pretty=oneline --abbrev-commit
* 59bc1cb conflict fixed
|\
| * 75a857c AND simple
* | 400b400 & simple
|/
* fec145a branch test
...
多人協(xié)作
當(dāng)你從遠(yuǎn)程倉庫克隆時啄巧,實(shí)際上Git自動把本地的master分支和遠(yuǎn)程的master分支對應(yīng)起來了寻歧,并且,遠(yuǎn)程倉庫的默認(rèn)名稱是origin秩仆。
要查看遠(yuǎn)程庫的信息码泛,用git remote:
$ git remote
origin
$ git remote -v
origin git@github.com:michaelliao/learngit.git (fetch)
origin git@github.com:michaelliao/learngit.git (push)
上面顯示了可以抓取和推送的origin的地址。如果沒有推送權(quán)限澄耍,就看不到push的地址噪珊。
推送分支
$ git push origin master
$ git push origin dev
但是,并不是一定要把本地分支往遠(yuǎn)程推送齐莲,那么痢站,哪些分支需要推送,哪些不需要呢选酗?
- master分支是主分支阵难,因此要時刻與遠(yuǎn)程同步;
- dev分支是開發(fā)分支芒填,團(tuán)隊(duì)所有成員都需要在上面工作呜叫,所以也需要與遠(yuǎn)程同步空繁;
- bug分支只用于在本地修復(fù)bug,就沒必要推到遠(yuǎn)程了朱庆,除非老板要看看你每周到底修復(fù)了幾個bug盛泡;
- feature分支是否推到遠(yuǎn)程,取決于你是否和你的小伙伴合作在上面開發(fā)椎工。
抓取分支
當(dāng)你的小伙伴從遠(yuǎn)程庫clone時饭于,默認(rèn)情況下,你的小伙伴只能看到本地的master分支维蒙。不信可以用git branch命令看看:
$ git branch
- master
現(xiàn)在掰吕,你的小伙伴要在dev分支上開發(fā),就必須創(chuàng)建遠(yuǎn)程origin的dev分支到本地颅痊,于是他用這個命令創(chuàng)建本地dev分支:
$ git checkout -b dev origin/dev
現(xiàn)在殖熟,他就可以在dev上繼續(xù)修改,然后斑响,時不時地把dev分支push到遠(yuǎn)程:
$ git commit -m "add /usr/bin/env"
[dev 291bea8] add /usr/bin/env
1 file changed, 1 insertion(+)
$ git push origin dev
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 349 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
fc38031..291bea8 dev -> dev
git pull也失敗了菱属,原因是沒有指定本地dev分支與遠(yuǎn)程origin/dev分支的鏈接,根據(jù)提示舰罚,設(shè)置dev和origin/dev的鏈接:
$ git branch --set-upstream dev origin/dev
Branch dev set up to track remote branch dev from origin.
小結(jié)
查看遠(yuǎn)程庫信息纽门,使用git remote -v;
本地新建的分支如果不推送到遠(yuǎn)程营罢,對其他人就是不可見的赏陵;
從本地推送分支,使用git push origin branch-name饲漾,如果推送失敗蝙搔,先用git pull抓取遠(yuǎn)程的新提交;
在本地創(chuàng)建和遠(yuǎn)程分支對應(yīng)的分支考传,使用git checkout -b branch-name origin/branch-name吃型,本地和遠(yuǎn)程分支的名稱最好一致;
建立本地分支和遠(yuǎn)程分支的關(guān)聯(lián)僚楞,使用git branch --set-upstream branch-name origin/branch-name勤晚;
從遠(yuǎn)程抓取分支,使用git pull镜硕,如果有沖突运翼,要先處理沖突。
Tag
在Git中打標(biāo)簽非常簡單兴枯,首先,切換到需要打標(biāo)簽的分支上:
$ git branch
* dev
master
$ git checkout master
Switched to branch 'master'
然后矩欠,敲命令git tag <name>就可以打一個新標(biāo)簽:
$ git tag v1.0
可以用命令git tag查看所有標(biāo)簽:
$ git tag
v1.0
Add tag to history commit
$ git log --pretty=oneline --abbrev-commit
6a5819e merged bug fix 101
cc17032 fix bug 101
7825a50 merge with no-ff
6224937 add merge
59bc1cb conflict fixed
400b400 & simple
75a857c AND simple
fec145a branch test
d17efd8 remove test.txt
...
$ git tag v0.9 6224937
$ git tag -a v0.1 -m "version 0.1 released" 3628164