$ mkdir learngit
$ cd learngit
$ pwd
/Users/michael/learngit
創建
$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/
增加
$ git add readme.txt
提交
$ git commit -m "wrote a readme file"
提交
$ git add file1.txt
$ git add file2.txt file3.txt
$ git commit -m "add 3 files."
狀態
$ git status
狀態區別
$ git diff readme.txt
記錄
$ git log
顯示記錄的方式
$ git log --pretty=oneline
回退到上一版本
$ git reset --hard HEAD^
回到之前的reset前的版本
$ git reset --hard 3628164
記錄以前命令路程
$ git reflog
命令可以查看工作區和版本庫里面最新版本的區別
git diff HEAD -- readme.txt
查看文件內容
$ cat readme.txt
命令git checkout -- readme.txt意思就是,把readme.txt文件在工作區的修改全部撤銷,這里有兩種情況:
$ git checkout -- readme.txt
一種是readme.txt自修改后還沒有被放到暫存區,現在,撤銷修改就回到和版本庫一模一樣的狀態;
一種是readme.txt已經添加到暫存區后,又作了修改,現在,撤銷修改就回到添加到暫存區后的狀態。
********
git checkout -- file命令中的--很重要,沒有--,就變成了“創建一個新分支”的命令
*******
git reset HEAD file可以把暫存區的修改撤銷掉(unstage),重新放回工作區:
$ git reset HEAD readme.txt
刪除文件 ,從文件管理中中刪除
$ rm test.txt
接着,一是確實要從版本庫中刪除該文件,那就用命令git rm刪掉,並且git commit
$ git rm test.txt
$ git commit -m "remove test.txt"
另一種情況是刪錯了,因為版本庫里還有呢,所以可以很輕松地把誤刪的文件恢復到最新版本:(版本庫沒有被刪的情況下)
$ git checkout -- test.txt
**********
…or create a new repository on the command line
*************
echo # learngit >> README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin https://github.com/liunnis/learngit.git
git push -u origin master
****************
…or push an existing repository from the command line
************
git remote add origin https://github.com/liunnis/learngit.git
git push -u origin master
就可以把本地庫的所有內容推送到遠程庫上:
$ git push -u origin master
從現在起,只要本地作了提交,就可以通過命令:
$ git push origin master
把本地master分支的最新修改推送至GitHub,現在,你就擁有了真正的分布式版本庫!
****
用命令git clone克隆一個本地庫:
$ git clone git@github.com:michaelliao/gitskills.git
**************************
在版本回退里,你已經知道,每次提交,Git都把它們串成一條時間線,這條時間線就是一個分支。
截止到目前,只有一條時間線,在Git里,這個分支叫主分支,
即master分支。HEAD嚴格來說不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是當前分支。
**********
首先,我們創建dev分支,然后切換到dev分支:
$ git checkout -b dev
git checkout命令加上-b參數表示創建並切換,相當於以下兩條命令:
$ git branch dev
$ git checkout dev
Switched to branch 'dev'
用git branch命令查看當前分支:
***********
現在,我們把dev分支的工作成果合並到master分支上:
$ git merge dev
合並完成后,就可以放心地刪除dev分支了:
$ git branch -d dev
用帶參數的git log也可以看到分支的合並情況:
$ git log --graph --pretty=oneline --abbrev-commit
遠程庫別一個方法
$ git remote add origin git@github.com:liunnis/learngit.git
$ git push -u origin master
准備合並dev分支,請注意--no-ff參數,表示禁用Fast forward:
$ git merge --no-ff -m "merge with no-ff" dev
工作區是干凈的,剛才的工作現場存到哪去了?用git stash list命令看看:
$ git stash list
工作現場還在,Git把stash內容存在某個地方了,但是需要恢復一下,有兩個辦法:
一是用git stash apply恢復,但是恢復后,stash內容並不刪除,你需要用git stash drop來刪除;
另一種方式是用git stash pop,恢復的同時把stash內容也刪了:
****************
你可以多次stash,恢復的時候,先用git stash list查看,然后恢復指定的stash,用命令:
$ git stash apply stash@{0}
現在,你終於接到了一個新任務:開發代號為Vulcan的新功能,該功能計划用於下一代星際飛船。
於是准備開發:
$ git checkout -b feature-vulcan
Switched to a new branch 'feature-vulcan'
雖然白干了,但是這個分支還是必須就地銷毀:
$ git branch -d feature-vulcan
現在我們強行刪除:
$ git branch -D feature-vulcan
當你從遠程倉庫克隆時,實際上Git自動把本地的master分支和遠程的master分支對應起來了,並且,遠程倉庫的默認名稱是origin。
要查看遠程庫的信息,用git remote:
$ git remote
origin
或者,用git remote -v顯示更詳細的信息:
$ git remote -v
推送分支
推送分支,就是把該分支上的所有本地提交推送到遠程庫。推送時,要指定本地分支,這樣,Git就會把該分支推送到遠程庫對應的遠程分支上:
$ git push origin master
如果要推送其他分支,比如dev,就改成:
$ git push origin dev
但是,並不是一定要把本地分支往遠程推送,那么,哪些分支需要推送,哪些不需要呢?
master分支是主分支,因此要時刻與遠程同步;
dev分支是開發分支,團隊所有成員都需要在上面工作,所以也需要與遠程同步;
bug分支只用於在本地修復bug,就沒必要推到遠程了,除非老板要看看你每周到底修復了幾個bug;
feature分支是否推到遠程,取決於你是否和你的小伙伴合作在上面開發。
總之,就是在Git中,分支完全可以在本地自己藏着玩,是否推送,視你的心情而定!
現在,模擬一個你的小伙伴,可以在另一台電腦(注意要把SSH Key添加到GitHub)或者同一台電腦的另一個目錄下克隆:
$ git clone git@github.com:michaelliao/learngit.git
Cloning into 'learngit'...
remote: Counting objects: 46, done.
remote: Compressing objects: 100% (26/26), done.
remote: Total 46 (delta 16), reused 45 (delta 15)
Receiving objects: 100% (46/46), 15.69 KiB | 6 KiB/s, done.
Resolving deltas: 100% (16/16), done.
當你的小伙伴從遠程庫clone時,默認情況下,你的小伙伴只能看到本地的master分支。不信可以用git branch命令看看:
$ git branch
* master
現在,你的小伙伴要在dev分支上開發,就必須創建遠程origin的dev分支到本地,於是他用這個命令創建本地dev分支:
$ git checkout -b dev origin/dev
現在,他就可以在dev上繼續修改,然后,時不時地把dev分支push到遠程:
$ git commit -m "add /usr/bin/env"
推送
$ git push origin dev
推送失敗,因為你的小伙伴的最新提交和你試圖推送的提交有沖突,解決辦法也很簡單,Git已經提示我們,先用git pull把最新的提交從origin/dev抓下來,然后,在本地合並,解決沖突,再推送:
$ git pull
git pull也失敗了,原因是沒有指定本地dev分支與遠程origin/dev分支的鏈接,根據提示,設置dev和origin/dev的鏈接:
$ git branch --set-upstream dev origin/dev
這回git pull成功,但是合並有沖突,需要手動解決,解決的方法和分支管理中的解決沖突完全一樣。解決后,提交,再push:
$ git commit -m "merge & fix hello.py"
[dev adca45d] merge & fix hello.py
$ git push origin dev
然后,敲命令git tag <name>就可以打一個新標簽:
$ git tag v1.0
可以用命令git tag查看所有標簽:
$ git tag
比方說要對add merge這次提交打標簽,它對應的commit id是6224937,敲入命令:
$ git tag v0.9 6224937
注意,標簽不是按時間順序列出,而是按字母排序的。可以用git show <tagname>查看標簽信息:
$ git show v0.9
還可以創建帶有說明的標簽,用-a指定標簽名,-m指定說明文字:
$ git tag -a v0.1 -m "version 0.1 released" 3628164
還可以通過-s用私鑰簽名一個標簽:
$ git tag -s v0.2 -m "signed version 0.2 released" fec145a
簽名采用PGP簽名,因此,必須首先安裝gpg(GnuPG),如果沒有找到gpg,或者沒有gpg密鑰對,
就會報錯:簽名采用PGP簽名,因此,必須首先安裝gpg(GnuPG),如果沒有找到gpg,或者沒有gpg密鑰對,就會報錯:
如果標簽打錯了,也可以刪除:
$ git tag -d v0.1
Deleted tag 'v0.1' (was e078af9)
如果要推送某個標簽到遠程,使用命令git push origin <tagname>:
$ git push origin v1.0
或者,一次性推送全部尚未推送到遠程的本地標簽:
$ git push origin --tags
如果標簽已經推送到遠程,要刪除遠程標簽就麻煩一點,先從本地刪除:
$ git tag -d v0.9
Deleted tag 'v0.9' (was 6224937)
然后,從遠程刪除。刪除命令也是push,但是格式如下:
$ git push origin :refs/tags/v0.9
比如,讓Git顯示顏色,會讓命令輸出看起來更醒目:
$ git config --global color.ui true
有些時候,你必須把某些文件放到Git工作目錄中,但又不能提交它們,
比如保存了數據庫密碼的配置文件啦,等等,
每次git status都會顯示Untracked files ...,
有強迫症的童鞋心里肯定不爽。
好在Git考慮到了大家的感受,這個問題解決起來也很簡單,
在Git工作區的根目錄下創建一個特殊的.gitignore文件,
然后把要忽略的文件名填進去,Git就會自動忽略這些文件。
假設你在Windows下進行Python開發,Windows會自動在有圖片的目錄下生成隱藏的縮略圖文件,
如果有自定義目錄,目錄下就會有Desktop.ini文件,
因此你需要忽略Windows自動生成的垃圾文件:
# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini
然后,繼續忽略Python編譯產生的.pyc、.pyo、dist等文件或目錄:
# Python:
*.py[cod]
*.so
*.egg
*.egg-info
dist
build
加上你自己定義的文件,最終得到一個完整的.gitignore文件,內容如下:
# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini
# Python:
*.py[cod]
*.so
*.egg
*.egg-info
dist
build
# My configurations:
db.ini
deploy_key_rsa
最后一步就是把.gitignore也提交到Git,
就完成了!當然檢驗.gitignore的標准
是git status命令是不是說working directory clean。
使用Windows的童鞋注意了,如果你在資源管理器里新建一個.gitignore文件,
它會非常弱智地提示你必須輸入文件名,但是在文本編輯器里“保存”或者“另存為”就可以把文件保存為.gitignore了。
************************
有沒有經常敲錯命令?比如git status?status這個單詞真心不好記。
如果敲git st就表示git status那就簡單多了,當然這種偷懶的辦法我們是極力贊成的。
我們只需要敲一行命令,告訴Git,以后st就表示status:
$ git config --global alias.st status
當然還有別的命令可以簡寫,很多人都用co表示checkout,ci表示commit,br表示branch:
$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch
--global參數是全局參數,也就是這些命令在這台電腦的所有Git倉庫下都有用。
在撤銷修改一節中,我們知道,命令git reset HEAD file可以把暫存區的修改撤銷掉(unstage),重新放回工作區。既然是一個unstage操作,就可以配置一個unstage別名:
$ git config --global alias.unstage 'reset HEAD'
當你敲入命令:
$ git unstage test.py
實際上Git執行的是:
$ git reset HEAD test.py
配置一個git last,讓其顯示最后一次提交信息:
$ git config --global alias.last 'log -1'
這樣,用git last就能顯示最近一次的提交:
$ git last
甚至還有人喪心病狂地把lg配置成了:
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
配置Git的時候,加上--global是針對當前用戶起作用的,如果不加,那只針對當前的倉庫起作用。
配置文件放哪了?每個倉庫的Git配置文件都放在.git/config文件中:
配置文件放哪了?每個倉庫的Git配置文件都放在.git/config文件中:
$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "origin"]
url = git@github.com:michaelliao/learngit.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
[alias]
last = log -1
而當前用戶的Git配置文件放在用戶主目錄下的一個隱藏文件.gitconfig中:
$ cat .gitconfig
[alias]
co = checkout
ci = commit
br = branch
st = status
[user]
name = Your Name
email = your@email.com
