Git&GitHub

廖雪峰教程

  • 0.使用GitHub
    0.1 添加到远程库
    0.2 从远程库克隆
    0.3 GitHub使用

  • 1.创建版本库

  • 2.时光穿梭机
    2.1 版本回退
    2.2 工作区和暂存区
    2.3 管理修改
    2.4 撤销修改
    2.5 删除文件

  • 3.分支管理
    3.1 创建与合并分支
    3.2 解决冲突
    3.3 分支管理策略
    3.4 Bug分支
    3.5 Feature分支
    3.6 多人协作

  • 4.标签管理
    4.1 创建标签
    4.2 操作标签

  • 5.自定义Git
    5.1 忽略特殊文件
    5.2 配置别名
    5.3 搭建Git服务器

  • 6.扩展
    6.1 rebase的使用

0.使用GitHub
生成SSH key,如果没有key的话,在用户主目录下面,执行下面语句:

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

该语句在用户主目录下面生成.ssh文件夹,文件夹中有两个文件,分别是id_rsa和id_rsa.pub,前者是私锁,不能告诉别人,后者是公锁,可以告诉别人,需要将后者即是id_rsa.pub中内容添加到GitHub的账户中,因为Git支持SSH协议,SSH key是GitHub用来识别代码是该用户提交过来的。

0.1 添加到远程库

git remote add origin https://github.com/Jayzen/demo_for_test.git 
#远程库的名字叫做origin,是默认的远程库的名称,其中demo_for_test是用户自定义的仓库名称
git push -u origin master
#第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令
git push origin master #第二次之后远程库的代码提交(对比第一次提交少了-u 参数)

0.2 从远程库克隆

git clone https://github.com/Jayzen/gitskill.git #自己的电脑这个可行
git clone git@github.com:Jayzen/gitskill.git

0.3 GitHub使用
如果要修改一个开源库,步骤如下:

fork   #fork一个项目,相当于在自己的github上面复制了一个相同的项目
git clone XX #在用户的本地复制该代码
git push  #用户本地修改代码之后,推送到GiHub中用户本身的目录下面
pull request #发起这个pull request,看作者是否接受

具体示意图见如:

Paste_Image.png

1.创建版本库

git init #初始化一个仓库
git add <file> #添加到仓库
git commit -m "some descriptions"  #提交到仓库,其中后面显示的-m是对本次提交的一次说明

2.时光穿梭机

git status #查看用户的状态
#如果只是对代码进行了修改,之后没有做任何改动,则会显Changes not staged for commit
#如果是在当前文件夹内添加了一个文件,之后没有做任何动作,则会显示untracked files
#如果对文件进行了修改,执行了add,没有执行commit,则会显示Changes to be committed
#如果代码全部提交到仓库中,则会显示nothing to commit, working directory clean
git diff #查看代码做了哪些修改,这种状态修改的说明只能是该文件没有执行git add之前才能看到

2.1 版本回退

git log #显示从近到远的提交日志
git log --pretty=oneline #将这些日志按照行显示
git reset --hard HEAD^ #将版本退回到上一次提交,其中HEAD^表示上一个版本,HEAD^^表示上上一个版本
git reset --hard commit_id #其中commit_id是commit过程中生成的id值
git reflog #记录head指向的每一次命令

head指向append GPL


Paste_Image.png

改为head指向add distributed

Paste_Image.png

2.2 工作区和暂存区
工作区其实就是git当前工作的文件夹。

把文件往Git版本库里添加的时候,是分两步执行的:
第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

Paste_Image.png

与此同时,在工作区中修改readme.txt文件和添加LICENSE,并且两次使用add命令,结果如下所示:

Paste_Image.png

以上的结果可以看出,两次add方法是将文件添加到暂存区中,执行git commit -m "fourth commit",得到以下的结果,暂存区是干净的。

Paste_Image.png

2.3 管理修改
Git跟踪的是修改,而不是文件。
git commit 提交给是是暂存区的内容,如果修改了文件,没有执行commit add,那么git commit对修改的文件内容无效。

git diff HEAD -- readme.txt  #查看工作区和版本库里面最新版本的区别

2.4 撤销修改
第一种情况:在工作区中修改,当时没有提交到暂存区

git checkout --file

命令git checkout -- readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:
一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
第二种情况:已经提交到暂存区

git reset HEAD file  #可以把暂存区的修改撤销掉,重新放回工作区
git checkout --file #重复第一种情况

其中

git reset  #命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本。

2.5 删除文件
当前工作区内有两个文件,分别是demo.rb和test.rb,其中在工作区中删除文件test.rb,则下面有两种情况:

#第一种:确实要删除该文件
git rm test.rb
git commit -m "remove test.rb"

自己测试了下,下面的代码也可以实现删除功能,因为版本控制跟踪的修改,而不是文件。
git add .
git commit -m "remove test.rb"

#第二种:
删除文件出现错误,因此相当于撤销修改
git checkout --test.rb #git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

3.1 创建和合并分支

git branch #查看分支
git branch <name> #创建分支
git checkout <name> #切换分支
git checkout -b <name> #创建+切换分支
git merge <name> #合并某分支到当前分支
git branch -d <name> #删除分支

一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点,每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长:

Paste_Image.png

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

Paste_Image.png

Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:

Paste_Image.png

假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:

Paste_Image.png

合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:

Paste_Image.png

3.2 解决冲突
当主分支和从分支在同一个地方进行修改了,并且进行合并之后,出现了冲突。

#生成另外一个分支,对这个分支进行修改,然后提交
git checkout -b feature
修改demo.rb中的内容
git add demo.rb
git commit -m "commit feature"

#回到master分支,对master分支进行修改,然后提交
git checkout master
修改demo.rb中的内容,并且和上一个部分修改同一个地方
git add demo.rb
git commit -m "commit master"

#对两个分支进行合并
git merge feature #出现了conflict

#修改conflict的内容,重新进行提交
git add demo.rb
git commit -m "final commit"

#上面的内容对conflict内容进行了修改,并且在master分支上进行了合并成功

#删除分支
git branch -d feature

#用图像形式显示合并
git log --graph --pretty=oneline --abbrev-commit

3.3 分支管理策略
每个人不应该在master分支上建立分支,而应该在dev分支上建立分支,每次提交应该针对dev分支,当发布版本时应该从dev分支上提交到master分支

如果按照上文的合并方式(fast forward)进行的话,如果删除了分支,就会丢失分支信息,因此这里可以采用禁用Fast forward模式,Git就会在merge时生成一个新的commit。

git checkout -b dev
修改demo.rb文件内容
git add demo.rb
git commit -m "commit dev"

#切换到master分支,禁止fast forward模式
git checkout master
git merge --no-ff -m "merge with no-ff" dev

#查看log,可以看到分支信息
git log --graph --pretty=oneline --abbrev-commit

下面图片显示分支信息:


Paste_Image.png

3.4 Bug分支
Bug分支的策略是把当前的分支存储起来,然后建立bug分支,修复好之后再对当前分支进行恢复。

git status #当前分支下的内容
git stash #对当前分支进行存储
git status #当对当前分支进行存储之后,发现当前分支的status是空的

#对bug分支进行修复
git checkout master
git checkout -b bug-issue
对demo.rb文件内容进行修改
git add demo.rb
git commit -m "bug commit"
git checkout master 
git merge --no-ff -m "merge bug commit" bug-issue
git status  #查看工作目录是空的

git slash list #查看slash
git slash apply #恢复后,stash内容并不删除,你需要用git stash drop来删除
git stash apply stash@{0} #恢复指定的slash
git slash pop #恢复的同时把stash内容也删了
git slash list #恢复后查看slash的内容也没有了

3.5 Feature分支
如果是开发新功能,最好是新建一个分支,如果这个分支已经被合并,那么删除这个分支使用:

git branch -d feature

如果这个分支没有被合并,删除这个分支,需要用到下面的语句:

git branch -D feature

3.6 多人协作
从远程克隆仓库也是分多种情况,第一种情况是只有一个master分支的情况下:

git clone XX  #远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin
git remote #origin  此代码是查看远程库的信息,远程库的默认信息是origin
git remote -v  #使用-v查看远程库更为详细的信息
  origin git@github.com:michaelliao/learngit.git (fetch)
  origin git@github.com:michaelliao/learngit.git (push)
git push origin master #推送master分支
git push origin dev  #推送dev分支

第二种情况是当远程库存在多个分支时候,使用git clone语句克隆代码,使用git branch语句只能查看master分支,为了显示其他分支,需要创建远程的origin的dev分支到本地:

git clone XX
git branch #master
#实际上被克隆的代码库有很多分支,而这里只能显示master分支
git checkout -b dev origin/dev
#使用上面的语句在本地建立dev分支,和远程库的dev分支对象起来,同时获得远程库的分支信息代码
#在dev分支上修改代码
git commit -m "add the dev" 
git push origin dev #将代码推送到远程库dev分支中

第三情况是处理冲突:两个人同时写作同一个代码库,比如在feature分支上面,一个人已经作为修改,另外一个人在此人修改之前已经git clone到本地,并且在feature同一个地方做了修改,因此会出现conflict。

#已经有其他用户在feature分支上面建立test.rb文件
#下面的代码都是在本地的feature分支上进行
git add test.rb
git commit -m "add the test.rb"
git push origin feature

上面的代码出现错误,根据提示可以知道,是因为出现了代码冲突,根据提示使用git pull。

git pull #如果存在no tracking information,说明本地分支和远程分支之间的链接关系没有建立
git branch --set-upstream-to=origin/feature feature #设置feature和origin/feature的链接
git pull #出现冲突及冲突提示
#冲突解决好之后重新提交
git commit -m "conflict commit"
git push origin feature

4.标签管理
标签是版本库的一个快照,若给版本库打了一个标签,就相当于在某个时候获取一个特定时间的版本库,标签和分支不同,分支可以移动,标签不能移动。
4.1 创建标签

git checkout master #切换到最新的master分支上
git tag v1.0 #给最新的分支贴上标签
git tag #查看所有标签
默认情况下标签是打在最新的提交的commit上,如果需要打在之前提交的commit上,需要如下的语句
git log --pretty=oneline --abbrev-commit  #显示commit id log
git tag v0.9 1234234  #其中1234234是commit id值,即将标签打在这个commit id中。
git show  v1.0 #查看某个版本的标签
git tag -a v0.1 -m "version 0.1 released" 3628164
#创建带有说明的标签,用-a指定标签名,-m指定说明文字

4.2 操作标签

git tag -d v0.9  #删除标签
git push origin v0.9 #因为标签都是在本地的,此代码是推送标签到远程
git push origin --tags #一次性推送全部尚未推送到远程的本地标签

#如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
#然后,从远程删除。删除命令也是push
git tag -d v0.9
git push origin :refs/tags/v0.9

5.自定义Git

git config --global color.ui true #设置颜色

5.1 忽略特殊文件
在工作区建立 .gitignore
ruby的示例文件可以在这里找到

5.2 配置别名
配置别名就是在将Git的命令用其他名字来表示,示例代码如下所示:

git config --global alias.co checkout
git config --global alias.ci commit
git config --global alias.br branch
#--global参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有用。

每个仓库的Git配置文件都放在.git/config文件中,其中别名就在[alias]后面,要删除别名,直接把对应的行删掉即可。

[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
中:

[alias] 
  co = checkout 
  ci = commit 
  br = branch 
  st = status
[user]
  name = Your Name 
  email = your@email.com

5.3 搭建Git服务器
见这里

6.扩展
6.1 rebase的使用
相关文档
在master分支上简历mywork分支,示意图如下所示:

Paste_Image.png

在mywork分支上提交两次代码,同时其他用户在master分支上提交了两次代码,示意图如下所示:

Paste_Image.png

在这里,你可以用"pull"命令把"origin"分支上的修改拉下来并且和你的修改合并; 结果看起来就像一个新的"合并的提交",示意图如下所示:

Paste_Image.png

但是,如果你想让"mywork"分支历史看起来像没有经过任何合并一样,可以用git rebase,代码如下所示:

git checkout mywork
git rebase origin

这些命令会把你的"mywork"分支里的每个提交(commit)取消掉,并且把它们临时 保存为补丁(patch)(这些补丁放到".git/rebase"目录中),然后把"mywork"分支更新 到最新的"origin"分支,最后把保存的这些补丁应用到"mywork"分支上。

Paste_Image.png

当'mywork'分支更新之后,它会指向这些新创建的提交(commit),而那些老的提交会被丢弃。 如果运行垃圾收集命令(pruning garbage collection), 这些被丢弃的提交就会删除。

Paste_Image.png

现在我们可以看一下用合并(merge)和用rebase所产生的历史的区别:

Paste_Image.png

6.2 修改最近一次的提交 commit --amend
该功能会修改最近一次的提交,使用commit --amend
比如最开始是这样的:

git log

需要对添加add的讲解进行修改,使用下面代码:

git add .
git commit --amend

上面的代码会跳出一个编辑页面,可以修改添加add的讲解的值,修改为添加add和commit的讲解,并且进行保存,使用git log操作,可以得到如下的结果:

git log

6.3 取消最新一次的提交 git revert head
下面的代码可以取消最近一次的提交

git revert HEAD

原本最初的提交branch如下所示:

Paste_Image.png

执行git revert HEAD之后,变为如下的结果

Paste_Image.png

就是说针对“添加pull的讲解”所变化的内容消失了。

6.4 使用reset来删除前面的几个提交
代码如下所示:

git reset --hard HEAD~~ #这是删除最前面的两个提交
git reset --hard HEAD~ #这是删除了最前面的一个提交
git reset --hard ORGI_HEAD #如果之前的reset出错了,该代码会返回最开始进行reset的位置

图片演示如下:

before reset
after reset

6.5 **使用cherry-pick将其他分支中的内容添加到主分支中 **
如下图所示:

Paste_Image.png

廖雪峰教程

  • 0.使用GitHub
    0.1 添加到远程库
    0.2 从远程库克隆
    0.3 GitHub使用

  • 1.创建版本库

  • 2.时光穿梭机
    2.1 版本回退
    2.2 工作区和暂存区
    2.3 管理修改
    2.4 撤销修改
    2.5 删除文件

  • 3.分支管理
    3.1 创建与合并分支
    3.2 解决冲突
    3.3 分支管理策略
    3.4 Bug分支
    3.5 Feature分支
    3.6 多人协作

  • 4.标签管理
    4.1 创建标签
    4.2 操作标签

  • 5.自定义Git
    5.1 忽略特殊文件
    5.2 配置别名
    5.3 搭建Git服务器

  • 6.扩展
    6.1 rebase的使用

0.使用GitHub
生成SSH key,如果没有key的话,在用户主目录下面,执行下面语句:

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

该语句在用户主目录下面生成.ssh文件夹,文件夹中有两个文件,分别是id_rsa和id_rsa.pub,前者是私锁,不能告诉别人,后者是公锁,可以告诉别人,需要将后者即是id_rsa.pub中内容添加到GitHub的账户中,因为Git支持SSH协议,SSH key是GitHub用来识别代码是该用户提交过来的。

0.1 添加到远程库

git remote add origin https://github.com/Jayzen/demo_for_test.git 
#远程库的名字叫做origin,是默认的远程库的名称,其中demo_for_test是用户自定义的仓库名称
git push -u origin master
#第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令
git push origin master #第二次之后远程库的代码提交(对比第一次提交少了-u 参数)

0.2 从远程库克隆

git clone https://github.com/Jayzen/gitskill.git #自己的电脑这个可行
git clone git@github.com:Jayzen/gitskill.git

0.3 GitHub使用
如果要修改一个开源库,步骤如下:

fork   #fork一个项目,相当于在自己的github上面复制了一个相同的项目
git clone XX #在用户的本地复制该代码
git push  #用户本地修改代码之后,推送到GiHub中用户本身的目录下面
pull request #发起这个pull request,看作者是否接受

具体示意图见如:

Paste_Image.png

1.创建版本库

git init #初始化一个仓库
git add <file> #添加到仓库
git commit -m "some descriptions"  #提交到仓库,其中后面显示的-m是对本次提交的一次说明

2.时光穿梭机

git status #查看用户的状态
#如果只是对代码进行了修改,之后没有做任何改动,则会显Changes not staged for commit
#如果是在当前文件夹内添加了一个文件,之后没有做任何动作,则会显示untracked files
#如果对文件进行了修改,执行了add,没有执行commit,则会显示Changes to be committed
#如果代码全部提交到仓库中,则会显示nothing to commit, working directory clean
git diff #查看代码做了哪些修改,这种状态修改的说明只能是该文件没有执行git add之前才能看到

2.1 版本回退

git log #显示从近到远的提交日志
git log --pretty=oneline #将这些日志按照行显示
git reset --hard HEAD^ #将版本退回到上一次提交,其中HEAD^表示上一个版本,HEAD^^表示上上一个版本
git reset --hard commit_id #其中commit_id是commit过程中生成的id值
git reflog #记录head指向的每一次命令

head指向append GPL


Paste_Image.png

改为head指向add distributed

Paste_Image.png

2.2 工作区和暂存区
工作区其实就是git当前工作的文件夹。

把文件往Git版本库里添加的时候,是分两步执行的:
第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

Paste_Image.png

与此同时,在工作区中修改readme.txt文件和添加LICENSE,并且两次使用add命令,结果如下所示:

Paste_Image.png

以上的结果可以看出,两次add方法是将文件添加到暂存区中,执行git commit -m "fourth commit",得到以下的结果,暂存区是干净的。

Paste_Image.png

2.3 管理修改
Git跟踪的是修改,而不是文件。
git commit 提交给是是暂存区的内容,如果修改了文件,没有执行commit add,那么git commit对修改的文件内容无效。

git diff HEAD -- readme.txt  #查看工作区和版本库里面最新版本的区别

2.4 撤销修改
第一种情况:在工作区中修改,当时没有提交到暂存区

git checkout --file

命令git checkout -- readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:
一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
第二种情况:已经提交到暂存区

git reset HEAD file  #可以把暂存区的修改撤销掉,重新放回工作区
git checkout --file #重复第一种情况

其中

git reset  #命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本。

2.5 删除文件
当前工作区内有两个文件,分别是demo.rb和test.rb,其中在工作区中删除文件test.rb,则下面有两种情况:

#第一种:确实要删除该文件
git rm test.rb
git commit -m "remove test.rb"

自己测试了下,下面的代码也可以实现删除功能,因为版本控制跟踪的修改,而不是文件。
git add .
git commit -m "remove test.rb"

#第二种:
删除文件出现错误,因此相当于撤销修改
git checkout --test.rb #git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

3.1 创建和合并分支

git branch #查看分支
git branch <name> #创建分支
git checkout <name> #切换分支
git checkout -b <name> #创建+切换分支
git merge <name> #合并某分支到当前分支
git branch -d <name> #删除分支

一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点,每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长:

Paste_Image.png

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

Paste_Image.png

Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:

Paste_Image.png

假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:

Paste_Image.png

合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:

Paste_Image.png

3.2 解决冲突
当主分支和从分支在同一个地方进行修改了,并且进行合并之后,出现了冲突。

#生成另外一个分支,对这个分支进行修改,然后提交
git checkout -b feature
修改demo.rb中的内容
git add demo.rb
git commit -m "commit feature"

#回到master分支,对master分支进行修改,然后提交
git checkout master
修改demo.rb中的内容,并且和上一个部分修改同一个地方
git add demo.rb
git commit -m "commit master"

#对两个分支进行合并
git merge feature #出现了conflict

#修改conflict的内容,重新进行提交
git add demo.rb
git commit -m "final commit"

#上面的内容对conflict内容进行了修改,并且在master分支上进行了合并成功

#删除分支
git branch -d feature

#用图像形式显示合并
git log --graph --pretty=oneline --abbrev-commit

3.3 分支管理策略
每个人不应该在master分支上建立分支,而应该在dev分支上建立分支,每次提交应该针对dev分支,当发布版本时应该从dev分支上提交到master分支

如果按照上文的合并方式(fast forward)进行的话,如果删除了分支,就会丢失分支信息,因此这里可以采用禁用Fast forward模式,Git就会在merge时生成一个新的commit。

git checkout -b dev
修改demo.rb文件内容
git add demo.rb
git commit -m "commit dev"

#切换到master分支,禁止fast forward模式
git checkout master
git merge --no-ff -m "merge with no-ff" dev

#查看log,可以看到分支信息
git log --graph --pretty=oneline --abbrev-commit

下面图片显示分支信息:


Paste_Image.png

3.4 Bug分支
Bug分支的策略是把当前的分支存储起来,然后建立bug分支,修复好之后再对当前分支进行恢复。

git status #当前分支下的内容
git stash #对当前分支进行存储
git status #当对当前分支进行存储之后,发现当前分支的status是空的

#对bug分支进行修复
git checkout master
git checkout -b bug-issue
对demo.rb文件内容进行修改
git add demo.rb
git commit -m "bug commit"
git checkout master 
git merge --no-ff -m "merge bug commit" bug-issue
git status  #查看工作目录是空的

git slash list #查看slash
git slash apply #恢复后,stash内容并不删除,你需要用git stash drop来删除
git stash apply stash@{0} #恢复指定的slash
git slash pop #恢复的同时把stash内容也删了
git slash list #恢复后查看slash的内容也没有了

3.5 Feature分支
如果是开发新功能,最好是新建一个分支,如果这个分支已经被合并,那么删除这个分支使用:

git branch -d feature

如果这个分支没有被合并,删除这个分支,需要用到下面的语句:

git branch -D feature

3.6 多人协作
从远程克隆仓库也是分多种情况,第一种情况是只有一个master分支的情况下:

git clone XX  #远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin
git remote #origin  此代码是查看远程库的信息,远程库的默认信息是origin
git remote -v  #使用-v查看远程库更为详细的信息
  origin git@github.com:michaelliao/learngit.git (fetch)
  origin git@github.com:michaelliao/learngit.git (push)
git push origin master #推送master分支
git push origin dev  #推送dev分支

第二种情况是当远程库存在多个分支时候,使用git clone语句克隆代码,使用git branch语句只能查看master分支,为了显示其他分支,需要创建远程的origin的dev分支到本地:

git clone XX
git branch #master
#实际上被克隆的代码库有很多分支,而这里只能显示master分支
git checkout -b dev origin/dev
#使用上面的语句在本地建立dev分支,和远程库的dev分支对象起来,同时获得远程库的分支信息代码
#在dev分支上修改代码
git commit -m "add the dev" 
git push origin dev #将代码推送到远程库dev分支中

第三情况是处理冲突:两个人同时写作同一个代码库,比如在feature分支上面,一个人已经作为修改,另外一个人在此人修改之前已经git clone到本地,并且在feature同一个地方做了修改,因此会出现conflict。

#已经有其他用户在feature分支上面建立test.rb文件
#下面的代码都是在本地的feature分支上进行
git add test.rb
git commit -m "add the test.rb"
git push origin feature

上面的代码出现错误,根据提示可以知道,是因为出现了代码冲突,根据提示使用git pull。

git pull #如果存在no tracking information,说明本地分支和远程分支之间的链接关系没有建立
git branch --set-upstream-to=origin/feature feature #设置feature和origin/feature的链接
git pull #出现冲突及冲突提示
#冲突解决好之后重新提交
git commit -m "conflict commit"
git push origin feature

4.标签管理
标签是版本库的一个快照,若给版本库打了一个标签,就相当于在某个时候获取一个特定时间的版本库,标签和分支不同,分支可以移动,标签不能移动。
4.1 创建标签

git checkout master #切换到最新的master分支上
git tag v1.0 #给最新的分支贴上标签
git tag #查看所有标签
默认情况下标签是打在最新的提交的commit上,如果需要打在之前提交的commit上,需要如下的语句
git log --pretty=oneline --abbrev-commit  #显示commit id log
git tag v0.9 1234234  #其中1234234是commit id值,即将标签打在这个commit id中。
git show  v1.0 #查看某个版本的标签
git tag -a v0.1 -m "version 0.1 released" 3628164
#创建带有说明的标签,用-a指定标签名,-m指定说明文字

4.2 操作标签

git tag -d v0.9  #删除标签
git push origin v0.9 #因为标签都是在本地的,此代码是推送标签到远程
git push origin --tags #一次性推送全部尚未推送到远程的本地标签

#如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
#然后,从远程删除。删除命令也是push
git tag -d v0.9
git push origin :refs/tags/v0.9

5.自定义Git

git config --global color.ui true #设置颜色

5.1 忽略特殊文件
在工作区建立 .gitignore
ruby的示例文件可以在这里找到

5.2 配置别名
配置别名就是在将Git的命令用其他名字来表示,示例代码如下所示:

git config --global alias.co checkout
git config --global alias.ci commit
git config --global alias.br branch
#--global参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有用。

每个仓库的Git配置文件都放在.git/config文件中,其中别名就在[alias]后面,要删除别名,直接把对应的行删掉即可。

[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
中:

[alias] 
  co = checkout 
  ci = commit 
  br = branch 
  st = status
[user]
  name = Your Name 
  email = your@email.com

5.3 搭建Git服务器
见这里

6.扩展
6.1 rebase的使用
相关文档
在master分支上简历mywork分支,示意图如下所示:

Paste_Image.png

在mywork分支上提交两次代码,同时其他用户在master分支上提交了两次代码,示意图如下所示:

Paste_Image.png

在这里,你可以用"pull"命令把"origin"分支上的修改拉下来并且和你的修改合并; 结果看起来就像一个新的"合并的提交",示意图如下所示:

Paste_Image.png

但是,如果你想让"mywork"分支历史看起来像没有经过任何合并一样,可以用git rebase,代码如下所示:

git checkout mywork
git rebase origin

这些命令会把你的"mywork"分支里的每个提交(commit)取消掉,并且把它们临时 保存为补丁(patch)(这些补丁放到".git/rebase"目录中),然后把"mywork"分支更新 到最新的"origin"分支,最后把保存的这些补丁应用到"mywork"分支上。

Paste_Image.png

当'mywork'分支更新之后,它会指向这些新创建的提交(commit),而那些老的提交会被丢弃。 如果运行垃圾收集命令(pruning garbage collection), 这些被丢弃的提交就会删除。

Paste_Image.png

现在我们可以看一下用合并(merge)和用rebase所产生的历史的区别:

Paste_Image.png

6.2 修改最近一次的提交 commit --amend
该功能会修改最近一次的提交,使用commit --amend
比如最开始是这样的:

git log

需要对添加add的讲解进行修改,使用下面代码:

git add .
git commit --amend

上面的代码会跳出一个编辑页面,可以修改添加add的讲解的值,修改为添加add和commit的讲解,并且进行保存,使用git log操作,可以得到如下的结果:

git log

6.3 取消最新一次的提交 git revert head
下面的代码可以取消最近一次的提交

git revert HEAD

原本最初的提交branch如下所示:

Paste_Image.png

执行git revert HEAD之后,变为如下的结果

Paste_Image.png

就是说针对“添加pull的讲解”所变化的内容消失了。

6.4 使用reset来删除前面的几个提交
代码如下所示:

git reset --hard HEAD~~ #这是删除最前面的两个提交
git reset --hard HEAD~ #这是删除了最前面的一个提交
git reset --hard ORGI_HEAD #如果之前的reset出错了,该代码会返回最开始进行reset的位置

图片演示如下:

before reset
after reset

6.5 **使用cherry-pick将其他分支中的内容添加到主分支中 **
如下图所示:

Paste_Image.png

添加commit的讲解添加到master分支中,代码如下所示:

git checkout master 
git cherry-pick 99daed2

#下面的提示代码是正常现象,说明提交成功
error: could not apply 99daed2... commit
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'

#但是如果出现冲突的话,需要添加如下的进行如下的操作
git add filename
git commit 

6.6 **使用rebase -i 汇合提交 **
这是做的事情是讲master上面最近的两次进行合并,汇合为一次提交,使用的代码如下:

git rebase -i HEAD~~

#上面的代码执行之后,会有下面的代码界面出现,将第二行的pick改为squash

pick 9a54fd4 添加commit的说明
pick 0d4a808 添加pull的说明

# Rebase 326fc9f..0d4a808 onto d286baa
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.


#编辑保存退出,然后出现了编辑界面,编辑里面的值,该值将成为合并commit的说明

示意图如下所示:

Paste_Image.png

就是将添加commit的讲解添加pull的讲解进行合并,成为一个commit。示意图如下所示:

Paste_Image.png

6.7 用rebase -i 修改提交
在这里修改添加commit的讲解

Paste_Image.png

代码修改如下所示:

git rebase -i HEAD~~

将第一行的pick改为eidt,保存之后退出
pick 9a54fd4 添加commit的说明
pick 0d4a808 添加pull的说明

# Rebase 326fc9f..0d4a808 onto d286baa
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

#打开sample.txt,适当地修改“commit的讲解”部分
git add sample.txt
git commit --amend

#已经commit,但是rebase操作还没结束。若要通知这个提交的操作已经结束,请指定 --continue选项执行rebase。
git rebase --continue

6.8 把分支内容合并成一个提交,并导入到master分支
示意图如下所示:

Paste_Image.png

把下面的一个分支合并成一个提交,并导入的master分支中,具体的代码如下所示:

git checkout master
git merge --squash issue1
#出现了下面的提示,说明提交成功
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requested
#出现下面的提示,则说明提交失败,出现了冲突
Auto-merging sample.txt
CONFLICT (content): Merge conflict in sample.txt
Squash commit -- not updating HEAD
Automatic merge failed; 
fix conflicts and then commit the result.

#说明发生了冲突,修改之后进行提交
git add sample.txt
git commit

6.9使用二分法查找bug
二分法的原理
代码演示如下:

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

推荐阅读更多精彩内容