Git&GitHub

作者: Jayzen | 来源:发表于2016-01-27 08:46 被阅读468次

    廖雪峰教程

    • 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  #进行了自动化测试,此代码可以测试出错误点
    

    相关文章

      网友评论

      本文标题:Git&GitHub

      本文链接:https://www.haomeiwen.com/subject/ltbdkttx.html