廖雪峰-Git教程-学习笔记

chapter 1: 如何创建版本库

  1. 初始化一个仓库

$ git init

  1. 添加文件到Git仓库的过程:

$ git add readme.txt

(没有消息提示, Unix哲学: 没有消息就是好消息)

$git commit -m 'write a readme file'

[master (root-commit) cb926e7] wrote a readme file
1 file changed, 2 insertions(+)
create mode 100644 readme.txt

chapter 2: 时光穿梭机

  1. 修改完文件后, 查看结果:

$ git status

$ 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 status命令可以让我们时刻掌握仓库当前的状态,上面的命令告诉我们,readme.txt被修改过了,但还没有准备提交的修改

  1. "Changes not staged for commit": 表示修改没有add到暂存区中等待提交, 也就是修改还只存在工作区

  2. 经过'$ git add readme.txt'后, 执行'$ git status', 输出了如下日志:

$ git status

On branch master

Changes to be committed:

(use "git reset HEAD <file>..." to unstage)

modified: readme.txt

"Changes to be committed": 表示修改已经add到了staged(暂存区), 等待被commit到HEAD master.

  1. 执行完'$ git commit - m 'add something'', 再执行"$ git status", 输出如下日志:

$ git status

On branch master

nothing to commit (working directory clean)

Git告诉我们当前没有需要提交的修改,而且,工作目录是干净(working directory clean)的

  1. 查看修改了什么内容

$ git diff readme.txt

section 1: 版本回退

  1. 查看历史记录

$ git log

$ git log
commit 3628164fb26d48395383f8f31179f24e0882e1e0
Author: Michael Liao askxuefeng@gmail.com
Date: Tue Aug 20 15:11:49 2013 +0800

append GPL

commit ea34578d5496d7dd233c827ed32a8cd576c5ee85
Author: Michael Liao askxuefeng@gmail.com
Date: Tue Aug 20 14:53:12 2013 +0800

add distributed

commit cb926e7ea50ad11b8f9e909c05226233bf755030
Author: Michael Liao askxuefeng@gmail.com
Date: Mon Aug 19 17:51:55 2013 +0800

wrote a readme file

git log命令显示从最新到最久的提交日志

如果想输出信息更见简洁:

$ git log --pretty=oneline

$ git log --pretty=oneline
3628164fb26d48395383f8f31179f24e0882e1e0 append GPL
ea34578d5496d7dd233c827ed32a8cd576c5ee85 add distributed
cb926e7ea50ad11b8f9e909c05226233bf755030 wrote a readme file

3628164fb26d48395383f8f31179f24e0882e1e0 是commit id(版本号).
每提交一个新版本, 实际上Git就会把它们自动串成一条时间线

  1. 如何将文件回退到上一个版本

Git中使用HEAD表示当前版本, 也就是最新提交的commit id 所在的版本. 上一个版本就是"HEAD^", 上上个版本就是"HEAD^^".
上100个版本就是"HEAD~100"

$ git reset --hard HEAD^

$ git reset --hard HEAD^
HEAD is now at ea34578 add distributed

此时, 你如果想回到最新的commit去. 只要找到那个版本的commit id(一般取前7位):

$ git reset --hard 3628164

就可以指定回到未来的某个版本!

Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD从指向“append GPL”:

git-head

改为指向“add distributed”:

git-head-move

然后顺便把工作区的文件更新了。所以你让HEAD指向哪个版本号,你就把当前版本定位在哪。

如果, 你在当前的命令行中找不到最新版本的commit id. 可以通过如下命令:

$ 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

3628164就是你要找的那个版本commit id.

section 2: 工作区和暂存区

工作区: working directory

版本库: Reposity, 工作区中的那个'.git'目录, 版本库中存了许多东西, 最重要的就是被称为'stage(or index)'的暂存区, 还有Git为我们自动创建的第一个分支master, 以及指向master的一个指针叫HEAD

git-repo

暂存区: stage(或index), 作为版本库的最重要的部分存在与'.git'目录中.

把文件往Git版本库里添加的时候,是分两步执行的:

第一步是用“git add”把文件添加进去,实际上就是把文件修改添加到暂存区;

第二步是用“git commit”提交更改,实际上就是把暂存区的所有内容提交到当前分支;

因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,commit就是往master分支上提交更改

从来没有add过的文件, 使用'git status'查看, 显示的是'Untracked files'

执行了git add命令后, 暂存区的状态如图:

git-stage

所以,git add命令实际上就是把要提交的所有修改放到暂存区(Stage),然后,执行git commit就可以一次性把暂存区的所有修改提交到分支

执行了git commit命令后, 暂存区就没有内容了, 修改的文件已经被commit到了master上:

现在版本库变成了这样,暂存区就没有任何内容了:

git-stage-after-commit

section 3: 管理修改

为什么Git比其他版本控制系统设计得优秀,因为Git跟踪并管理的是修改,而非文件。

你会问,什么是修改?比如你新增了一行,这就是一个修改,删除了一行,也是一个修改,更改了某些字符,也是一个修改,删了一些又加了一些,也是一个修改,甚至创建一个新文件,也算一个修改

如果你进行了如下操作:

第一次修改 -> git add -> 第二次修改 -> git commit

则只有第一次修改的内容被提交到了reposity中, 因为只有第一次修改被add到stage中

每次修改,如果不add到暂存区,那就不会加入到commit中

section 4: 撤销修改

  1. 丢弃工作区的修改:

$ git checkout -- readme.txt
命令git checkout -- readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:

一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;

一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。

总之,就是让这个文件回到最近一次git commit或git add时的状态。

注意: '--'很重要, 如果没有, 将变成了"创建一个新分支"的命令

  1. 撤销掉暂存区的修改(unstage) , 重新放回到工作区

$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt

git reset命令既可以回退版本, 也可以把暂存区中的修改回退到工作区

还记得如何回退版本吗?

section 5: 删除文件

在本地删除了文件"rm text.txt", 立刻可以通过"git status"看到变化

  1. 如果你要从版本库中删除文件

$ 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

  1. 如果你错删了文件, 把误删的文件恢复到最新版本:

$ git checkout -- test.txt
git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

chapter 3: 远程仓库

  1. 配置github

第1步:创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:

$ ssh-keygen -t rsa -C "youremail@example.com"

如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人.

第2步:登陆GitHub,打开“Account settings”,“SSH Keys”页面:

然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容

chapter: 创建和合并分支

  1. git中默认有一个主分支, 叫做master. HEAD严格来说不是指向提交, 而是指向master分支, 而master才是指向提交的. 所以HEAD就是指向当前的分支.

  2. 每一次提交, master分支都会向前移动一步

  3. 当你创建新的分支如dev时, Git新建了一个指针叫dev, 指向master相同的提交, 再把HEAD指向dev, 就表示当前分支在dev上:

git-br-create

从现在开始, 对工作区的修改和提交都市针对dev分支了, 比如新提交一次后, dev分支就向前移动一步, 而master指针不变:

git-br-dev-fd

假如我们在dev中的工作完成了, 就可以把dev合并到master上.

创建分支, 并切换到分支:

$ git checkout -b 15_learn_git_flow -t master

git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:

$ git branch dev
$ git checkout dev
Switched to branch 'dev'
然后,用git branch命令查看当前分支:

$ git branch

  • dev
    master
    git branch命令会列出所有分支,当前分支前面会标一个*号。

然后,我们就可以在dev分支上正常提交,比如对readme.txt做个修改,加上一行:

Creating a new branch is quick.
然后提交:

$ git add readme.txt
$ git commit -m "branch test"
[dev fec145a] branch test
1 file changed, 1 insertion(+)
现在,dev分支的工作完成,我们就可以切换回master分支:

$ git checkout master
Switched to branch 'master'
切换回master分支后,再查看一个readme.txt文件,刚才添加的内容不见了!因为那个提交是在dev分支上,而master分支此刻的提交点并没有变:

git-br-on-master

现在,我们把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

问题: 如何创建远程的分支?

  1. 先在本地创建分支

$ git checkout -b 18_learn_git_flow -t master

  1. 将本地的分支push到远程

$ git push origin 18_learn_git_flow

section 4: Bug分支

修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;

当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场。

查看全部的工作现场 :

$ git stash list

恢复工作现场:

方式一: 通过git stash apply  stash@{0}, 但恢复后, stash内容并不删除, 需要使用git stash drop来删除 

方式二: 通过 git stash pop, 恢复的同时把stash内容也删掉. 

section 5: Feature分支

删除分支:

$ git branch -d feature1 --- 删除本地分支1, 如果该分支没有被merge request, 则不能删除

$ git branch -D feature1 --- 删除本地分支, 不管该branch有没有merge request

删除远程分支:

$ git push origin --delete 18_learn_git_flow

或者, 通过推送一个空的branch到远程达到删除的目的:

$ git branch -d branchName

$ git push origin :branchName

删除不存在对应远程分支的本地分支:

假设这样一种情况:

1. 我创建了本地分支b1并pull到远程分支 origin/b1;
2. 其他人在本地使用fetch或pull创建了本地的b1分支;
3. 我删除了 origin/b1 远程分支;
4. 其他人再次执行fetch或者pull并不会删除这个他们本地的 b1分支,运行 git branch -a 也不能看出这个branch被删除了,如何处理


使用$ git remote show origin 查看b1的状态



如果显示b1是stable, 使用 $ git remote prune origin 可以将其从本地版本库中删除 

或者, 更简单的方式是, 使用 $ git fetch -p , 它在fetch之后删除掉没有与远程分支对应的本地分支

重命名本地分支:

$ git branch -m oldName newName 

重命名远程分支, 其实也就是先删除远程分支, 然后将重命名后的本地分支推送上去:

$ git push --delete origin oldName

$ git branch -m oldName newName

$ git push origin newName 

chapter: 多人协作

因此,多人协作的工作模式通常是这样:

首先,可以试图用git push origin branch-name推送自己的修改;

如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;

如果合并有冲突,则解决冲突,并在本地提交;

没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!

如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --track branch-name origin/branch-name。

这就是多人协作的工作模式,一旦熟悉了,就非常简单。

小结
查看远程库信息,使用git remote -v;

本地新建的分支如果不推送到远程,对其他人就是不可见的;

从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;

在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;

建立本地分支和远程分支的关联,使用git branch --track branch-name origin/branch-name;

从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。

chapter: 标签管理

发布一个版本时,我们通常先在版本库中打一个标签,这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。

Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的

命令git tag name用于新建一个标签,默认为HEAD,也可以指定一个commit id;

-a tagname -m "blablabla..."可以指定标签信息;

-s tagname -m "blablabla..."可以用PGP签名标签;

命令git tag可以查看所有标签;

$ git checkout master

$ git tag v1.0

$ git tag v1.0 36564232

$ git tag -a v1.0 -m "version 1.0 released" 36564232

查看tag的详情内容:

$ git show tagname

删除标签:

$ git tag -d v1.0

因为创建的标签都只存储在本地, 不会自动推送到远程, 所以, 打错了标签可以在本地安全删除.

如果要推送某个标签到远程, 使用命令:

$ git push origin tagname

或者, 一次性推送全部尚未推送到远程的本地标签:

$ git push origin --tags 

删除远程标签(其实是推送一个空的tag到远程tag达到删除目的):

1) 先删除本地的标签: $ git tag -d v.0 

2) 然后从远程删除:   $ git push origin :refs/tags/v1.0

或者, 1.7以后可以这么做:

$ git push origin --delete tag v1.0

获取远程的tag:

$ git fetch origin tag <tagname>

小结
命令git push origin tagname可以推送一个本地标签;

命令git push origin --tags可以推送全部未推送过的本地标签;

命令git tag -d tagname可以删除一个本地标签;

命令git push origin :refs/tags/tagname可以删除一个远程标签。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容