初始化一个Git仓库,使用git init命令。
添加⽂文件到Git仓库,分两步:
• 第一步,使用命令git add ,注意,可反复多次使用,添加多个文件;
• 第二步,使用命令git commit,完成。
git status命令可以让我们时刻掌握仓库当前的状态,上⾯面的命令告诉我们,readme.txt被
修改过了,但还没有准备提交的修改。
的。比如你休假两周从国外回来,第⼀一天上班时,已经记不清上次怎么修改的
readme.txt,所以,需要用git diff这个命令看看:
git diff readme.txt
当然了,在实际⼯工作中,我们脑子里怎么可能记得⼀一个⼏几千⾏行的文件每次都改了什么内容,
不然要版本控制系统干什么。版本控制系统肯定有某个命令可以告诉我们历史记录,在Git
中,我们用git log命令查看:
如果嫌输出信息太多,看得眼花缭乱的,可以试试加上
--pretty=oneline参数:
git log --pretty=oneline
首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表⽰示当前版本,也就是最新的
提交“ 3628164...882e1e0”(注意我的提交ID和你的肯定不一样),上一个版本就是
HEAD^,上上一个版本就是HEAD^^,当然往上100 个版本写100个^比较容易数不过来,
所以写成HEAD~100。
现在,我们要把当前版本“append GPL”回退到上⼀一个版本“add distributed”,就可
以使⽤用git reset命令:
git reset --hard HEAD^
Git提供了一个命令git reflog⽤用来记录你的每一次命令:
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
终于舒了⼝口⽓气,第二行显⽰示“append GPL”的commit id是3628164,现在,你⼜又可以乘
坐时光机回到未来了。
现在总结⼀一下:
• HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命
令 git reset --hard commit_id。
• 穿梭前,⽤用git log可以查看提交历史,以便确定要回退到哪个版本。
• 要重返未来,⽤用git reflog查看命令历史,以便确定要回到未来的哪个版本。
git checkout -- readme.txt
命令git checkout -- readme.txt意思就是,把readme.txt⽂文件在⼯工作区的修改全部撤销,这
⾥里有两种情况:
一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一
样的状态;
一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存
区后的状态。
总之,就是让这个文件回到最近一次git commit或git add时的状态。
现在,看看readme.txt的⽂文件内容:
$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
文件内容果然复原了。
git checkout -- file命令中的“--”很重要,没有“--”,就变成了“创建⼀一个新分⽀支”的命
令,我们在后⾯面的分⽀支管理中会再次遇到git checkout命令。
Git同样告诉我们,.用命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重
新放回.工作区:
git reset HEAD readme.txt
git reset命令既可以回退版本,也可以把暂存区的修改回退到.工作区。当我们.用HEAD时,
表.示最新的版本。
还记得如何丢弃.工作区的修改吗?
git checkout -- readme.txt
git status
# On branch master
nothing to commit (working directory clean)
整个世界终于清静了!
现在,假设你不但改错了东.西,还从暂存区提交到了版本库,怎么办呢?还记得版本回退.一
节吗?可以回退到上.一个版本。不过,这是有条件的,就是你还没有把.自.己的本地版本库推
送到远程。还记得Git是分布式版本控制系统吗?我们后.面会讲到远程版本库,.一旦你
把“stupid boss”提交推送到远程版本库,你就真的惨了……
############### 重点
总结: 没有 git add 之前的修改 用 git checkout -- readme.txt 撤销修改
git add 之后的修改: 先执行 git reset HEAD file,后 执行 git checkout -- readme.txt
git commit之后的修改 用 git reset --hard commit_id
如果已经 git push了, ohYear , 你没得救了.
场景1:当你改乱了.工作区某个.文件的内容,想直接丢弃.工作区的修改时,.用命令git
checkout -- file。 (git add 之前 )
场景2:当你不但改乱了.工作区某个.文件的内容,还添加到了暂存区时,想丢弃修改,分两
步,第.一步.用命令git reset HEAD file,就回到了场景1,第.二步按场景1操作。(git add之后)
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退.一节,不
过前提是没有推送到远程库。(git commit 之后)
############### 重点
一是确实要从版本库中删除该⽂文件,那就用命令git rm删掉,并且
commit:
git rm test.txt
rm 'test.txt'
git commit -m "remove test.txt"
[master d17efd8] remove test.txt
1 file changed, 1 deletion(-)
delete mode 100644 test.txt
现在,⽂文件就从版本库中被删除了。
另一种情况是删错了,因为版本库⾥里还有呢,所以可以很轻松地把误删的⽂文件恢复到最新版
本:
git checkout -- test.txt
git checkout其实是⽤用版本库⾥里的版本替换⼯工作区的版本,⽆无论⼯工作区是修改还是删除,都
可以“一键还原”。
要关联.一个远程库,使.用命令git remote add origin git@server-name:path/repo-name.git;
关联后,使.用命令git push -u origin master第.一次推送master分.支的所有内容;
此后,每次本地提交后,只要有必要,就可以使.用命令git push origin master推送最新修
改;
分布式版本系统的最.大好处之.一是在本地.工作完全不需要考虑远程库的存在,也就是有没有
联..网都可以正常.工作,.而SVN在没有联..网的时候是拒绝干活的!当有..网络的时候,再把本地
提交推送.一下就完成了同步,真是太.方便了!
分支:
首先,我们创建dev分⽀支,然后切换到dev分⽀支:
git checkout -b dev
Switched to a new branch 'dev'
git checkout命令加上-b参数表⽰示创建并切换,相当于以下两条命令:
git branch dev
git checkout dev
Switched to branch 'dev'
然后,⽤用git branch命令查看当前分⽀支:
git branch
* dev
master
git branch命令会列出所有分⽀支,当前分⽀支前⾯面会标⼀一个*号。
现在,我们把dev分⽀支的⼯工作成果合并到master分⽀支上:
$ git merge dev
Updating d17efd8..fec145a
Fast-forward
readme.txt | 1 +
1 file changed, 1 insertion(+)
git merge命令⽤用于合并指定分⽀支到当前分⽀支。合并后,再查看readme.txt的内容,就可以
看到,和dev分支的最新提交是完全一样的。
注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把
master指向dev的当前提交,所以合并速度非常快。
当然,也不是每次合并都能Fast-forward,我们后⾯面会将其他⽅方式的合并。
合并完成后,就可以放⼼心地删除dev分支了:
$ git branch -d dev
Deleted branch dev (was fec145a).
删除后,查看branch,就只剩下master分⽀支了:
$ git branch
* master
因为创建、合并和删除分⽀支⾮非常快,所以Git⿎鼓励你使用分支完成某个任务,合并后再删掉
分支,这和直接在master分⽀支上工作效果是一样的,但过程更安全。
Git鼓励⼤大量使用分支:
查看分支:git branch
创建分支:git branch name
切换分支:git checkout name
创建+切换分支:git checkout -b name
合并某分支到当前分支:git merge name
删除分支:git branch -d name
.用带参数的git log也可以看到分⽀支的合并情况:
$ git log --graph --pretty=oneline --abbrev-commit
现在,我们切换回master:
$ git checkout master
Switched to branch 'master'
准备合并dev分.支,请注意--no-ff参数,表.示禁.用“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(+)
因为本次合并要创建.一个新的commit,所以加上-m参数,把commit描述写进去。
合并后,我们.用git log看看分.支历史:
$ git log --graph --pretty=oneline --abbrev-commit
开发.一个新feature,最好新建.一个分支;
如果要丢弃.一个没有被合并过的分支,可以通过git branch -D name强.行删除。
信可以用git branch命令看看:
$ git branch
* master
现在,你的⼩小伙伴要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是他
⽤用这个命令创建本地dev分支:
$ git checkout -b dev origin/dev
现在,他就可以在dev上继续修改,然后,时不时地把dev分支push到远程:
git pull也失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,
设置dev和origin/dev的链接:
$ git branch --set-upstream dev origin/dev
Branch dev set up to track remote branch dev from origin.
再pull:
$ git pull
Auto-merging hello.py
CONFLICT (content): Merge conflict in hello.py
Automatic merge failed; fix conflicts and then commit the result.
这回git pull成功,但是合并有冲突,需要⼿手动解决,解决的方法和分支管理中的解决冲突完
全⼀一样。解决后,提交,再push.
多人协作的⼯工作模式通常是这样:
1. ⾸首先,可以试图用git push origin branch-name推送自己的修改;
2. 如果推送失败,则因为远程分⽀支⽐比你的本地更新,需要先用git pull试图合并;
3. 如果合并有冲突,则解决冲突,并在本地提交;
4. 没有冲突或者解决掉冲突后,再⽤用git push origin branch-name推送就能成功!
如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没
有创建,用命令git branch --set-upstream branch-name origin/branch-name。
这就是多人协作的工作模式,一旦熟悉了,就非常简单.
查看远程库信息,使⽤用git remote -v;
• 本地新建的分支如果不推送到远程,对其他⼈人就是不可见的;
• 从本地推送分支,使⽤用git push origin branch-name,如果推送失败,先⽤用git pull抓
取远程的新提交;
• 在本地创建和远程分支对应的分⽀支,使用git checkout -b branch-name origin/branchname,
本地和远程分支的名称最好一致;
• 建⽴立本地分支和远程分支的关联,使⽤用git branch --set-upstream branch-name
origin/branch-name;
• 从远程抓取分支,使⽤用git pull,如果有冲突,要先处理冲突。
创建标签:
命令git tag name⽤用于新建⼀一个标签,默认为HEAD,也可以指定⼀一个commit id;
-a tagname -m "blablabla..."可以指定标签信息;
命令git tag可以查看所有标签;
命令git push origin tagname可以推送⼀一个本地标签;
• 命令git push origin --tags可以推送全部未推送过的本地标签;
• 命令git tag -d tagname可以删除⼀一个本地标签;
• 命令git push origin :refs/tags/tagname可以删除⼀一个远程标签。
...