git学习笔记2

git学习笔记之二


从廖大神的git教程的分支管理开始

  1. 分支的创建与合并
    • 首先,创建dev分支,然后切换到dev分支
      git学习笔记2
      git checkout 命令加上-b 参数表示创建并切换,相当于以下两条命令:
      $ git branch dev
      $ git checkout dev
      Switched to branch 'dev'
      然后用git branch命令查看当前分支:
      git学习笔记2
      git branch命令会列出所有分支,当前分支前面会标一个*号
    • 然后 我们就可以在dec分支上正常提交,比如对readme.txt做个修改,然后提交:
      git学习笔记2
    • 现在,dev分支的工作完成,可以切换回master分支:
      git checkout master
      Switch to branch 'master'
    • 切换回master分支后,再查看一下readme.txt文件,刚才添加的内容不见了。因为提交是在dev分支上,而master分支此刻的提交点并没有变。
    • 现在我们把dev分支的工作成果合并到master分支上:
      git学习笔记2
      git merge 命令用于合并制定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到是和dev分支的最新提交是完全一样的。
      注意上面的Fast-forward信息,Git告诉我们,这次合并是”快进模式”,也就是直接把master指向dev当前提交,所以合并速度非常快。当然也不是每次合并都能Fast-forward,后面会讲其他方式的合并。
    • 合并完成后,就可以删除dev分支了:
      git branch -d dev
      Deleted branch dev (was e4b32fb)
      删除后,使用git branch查看分支,就发现只剩下master分支了。
    • 小结
      • Git鼓励大量使用分支:
      • 查看分支 git branch
      • 创建分支 git branch <name>
      • 切换分支 git checkout <name>
      • 创建+切换分支 git checkout -b <name>
      • 合并某分支到当前分支 git merge <name>
      • 删除分支 git branch -d <name>
  2. 解决冲突
    • 创建并切换到新的feature1分支,
      git checkout -b feature1
      Switch to a new branch 'feature1'
    • 修改readme.txt的最后一行
      Creating a new branch is quick AND simple.
    • feature1分支上提交
      $ git add readme.txt
      $ git commit -m "AND simple"
      [feature1 0e8692f] AND simple
      1 file changed, 1 insertion(+), 1 deletion(-)
    • 切换到master分支
      $ git checkout master
      Switched to branch 'master'
      Your branch is ahead of 'origin/master' by 1 commit.
    • master分支上把 readme.txt文件的最后一行改为:Creating a new branch is quick & simple.
    • master分支上提交。现在,master分支和feature1分支各自的readme.txt都分别有新的提交。这种情况下,Git无法执行快速合并,只能吧各自的修改合并起来,但这种合并就可能会有冲突。我们合并看一下:
      $ git merge feature1
      Auto-merging readme.txt
      CONFLICT (content): Merge conflict in readme.txt
      Automatic merge failed; fix conflicts and then commit the result.
    • 冲突了!GIT告诉我们 readme.txt文件存在冲突,必须手动解决冲突后再提交。git status也可以告诉我们冲突的文件:
      $ git status
      On branch master
      Your branch is ahead of 'origin/master' by 2 commits.
      Unmerged paths:
      (use "git add/rm <file>..." as appropriate to mark resolution)
      both modified: readme.txt
      no changes added to commit (use "git add" and/or "git commit -a")
    • 我们查看readme.txt中的内容,冲突基本和SVN的类型一样,我们手动修改后,再进行添加和提交操作就OK了,最后别忘了删除feature1分支。
    • 小结
      • 当git无法自动合并分支时,就必须首先解决冲突。冲突解决后,再提交,完成合并
      • git log --graph 命令可以看到分支合并图。
  3. 分支管理策略
    • 通常,合并分支时,如果可能,git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
    • 如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
    • 我们实战一下--no-ff方式的git merge
      先创建并切换dev分支:
      $ git checkout -b dev
      Switched to a new branch 'dev'
    • 修改readme.txt文件,并提交一个新的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
    • 分支策略
      在实际开发中,应该按照几个基本原则进行分支管理:
      • 首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不在此分支上干活
      • 干活都在dev分支上,也就是说 dev分支是不稳定的,到某个时候,比如版本发布时,再把dev分支合并到master上,在master分支发布新版本
    • 小结
      • Git分支十分强大,在团队开发中应该充分应用
      • 合并分支时,加上 --no-ff 参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而 Fast foward合并就看不出来曾经做过合并
        1. BUG分支
    • 软件开发中,有bug很正常,有bug就需要修复,在GIT中,由于分支很强大,所以每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除
    • 当我们需要修复一个bug时,我们很自然的想到创建一个新分支来修复它,但是当前正在dev 分支上进行的工作只进行到一半,还没办法提交,而且BUG还需要很快修复。怎么办?
    • 为了解决上述问题,Git提供了一个 git stash 命令,可以把当前工作现场储藏起来,等以后恢复现场后继续工作:
      git stash
      Saved working directory and index state WIP on dev: 6224937 add merge
      HEAD is now at 6224937 add merge
    • 现在再用git status查看工作区,就是干净的(除非有没有被Git管理的文件),然后就可以放心的创建分支修复BUG了。
    • 首先确定要在哪个分支上修复BUG,假设需要在master分支上修复,就从master创建临时分支
    • 修复BUG后,切换到master分支,并完成合并,最后删除issue-101分支
    • 然后切换回dev分支,由于我们刚才隐藏了一个文件,所以此时工作区是干净的,我们先用 git stash list 命令看看,发现工作现场还在,接下来我们需要回复工作现场,有两个办法
      • 一是用 git stash apply 恢复,但是恢复后,stash内容并不删除,需要用 git stash drop 来删除
      • 另一种使用 git stash pop ,恢复的同时把stash内容也删了。
    • 小结
      • 修复BUG时,我们会通过创建新的分支进行修复,然后合并,最后删除
      • 当手头工作没有完成时,先把工作现场 git stash 一下,然后修复BUG ,修复后,在 git stash pop ,回到工作现场
  4. feature 分支
    • 软件开发过程中,总会有新功能会添加进来。添加一个新功能时,肯定不能因为一下实验性质的代码,把主分支搞乱了,所以 每添加一个新功能。最好新建一个feature分支。在上面开发完毕后,合并。最后删除该feature分支
    • 小结
      • 开发一个新feature,最好新建一个分支
      • 如果要丢弃一个没有被合并过的分支,可以通过 git branch -D <name> 强行删除
  5. 多人协作
    • 当你从远程仓库克隆代码时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称室origin,要查看远程库的信息,用 git remote 或者 用 git remote -v 显示更详细的信息:
      git学习笔记2
      上面显示了可以抓取和推送的 origin地址,如果没有推送权限,就看不到push的地址
    • 推送分支,就是把该分支上的所有本地提交推送到远程库,推送时,要制定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:
      git push origin master
      git学习笔记2
      如果要推送其他分支,比如dev,就改成
      git push origin dev
      git学习笔记2
    • 但是,并不是一定要把本地分支往远程推送,下面是是否要推送的判断准则
      • master分支是主分支,因此要时刻与远程同步
      • dev 分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步
      • bug分支只用于在本地修复BUG,就没必要推到远程了,除非领导要看你的bug修复量
      • feature分支是否推送到远程,取决于你是否和同事合作在上面开发
      • 总之,在GIT中,分支完全可以在本地自己隐藏,是否推送视情况而定
    • 抓取分支,多人协作时,大家都会往 masterdev 分支上推送各自的修改,
    • 现在,模拟一个小伙伴,可以在另一目录下克隆:
      git学习笔记2
    • 当你的小伙伴从远程库clone时,默认情况下,只能看到本地的 master 分支
    • 现在,小伙伴要在 dev 分支上开发,就必须创建远程 origin 的分支到本地,于是他用这个命令创建本地 dev 分支:
      git学习笔记2
      现在,他就可以在 dev上继续修改,然后,时不时的吧 dev 分支 push 到远程:
      git学习笔记2
    • 你的小伙伴已经向 origin/dev 分支推送了他的提交,而碰巧你也对同样的文件做了修改,并试图推送:
      git学习笔记2
      推送失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法很简单,Git已经提示我们,先用 git pull 把最新的提交从 origin/dev抓下来,然后在本地合并,解决冲突,在推送。
    • 然而, git pull 也失败了,原因是没有指定本地 dev 分支与远程 origin/dev 分支的链接,根据提示,设置 devorigin/dev 的连接,再pull。这回 git pull 成功,但是合并有冲突,需要手动解决,解决办法和分支管理中的解决冲突完全一样(类似 SVN 解决冲突) 解决后,提交,再push
    • 因此,多人协作的工作模式通常是这样:
      • 首先,可以试图用 git push origin branch -name 推送自己的修改
      • 如果推送失败,则因为远程分支比你本地更新,需要先用 git pull 试图合并
      • 如果合并有冲突,则解决冲突,并在本地提交
      • 没有冲突或者解决掉冲突后,再用 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/branch-name,本地和远程分支的名称最好一致
      • 建立本地分支和远程分支的关联,使用 git branch --set-upstream branch-name origin/branch-name
      • 从远程抓取分支,使用 git pull ,如果有冲突,要先处理冲突。
  6. 标签管理

    • 创建标签,首先切换到需要打标签的分支上
    • 然后输入命令 git tag v1,0 就可以打一个新标签,可以用命令 git tag 查看所有标签
      git学习笔记2
    • 默认标签是打在最新提交的commit上的,有时间,如果忘了打标签,比如,现在是周五,但应该在周一打的标签没有打,怎么办?方法是找到历史提交的commit id ,然后打上就可以了:
      git学习笔记2
      比如,要对 add merge这次提交打标签,看它对应的 commit id 是2f0e36c,键入命令:git tag v.09 <commit id>,再用命令 git tag 查看标签:
      git学习笔记2
    • 注意,标签不是按时间顺序列出,而是按字母排序的,可以用 git show <tagname> 查看标签信息,可以看到 v0.9确实打在 add merge 这次提交上。
      git学习笔记2
    • 还可以创建带有说明的标签,用 -a指定标签名,-m指定说明文字。用命令 git show tagname 可以看到说明文字:
      git学习笔记2
    • 还可以通过 -s 用私钥签名一个标签。签名采用PGP签名,因此,必须首先安装gpg(GnuPG),如果没有找到gpg,或者没有gpg**对,就会报错,如果报错,请参考GnuPG帮助文档配置key
    • 用命令 git show <tagname> 可以看到PGP签名信息,用PGP签名的标签是不可伪造的,因为可以验证PGP签名。
    • 小结
      • 命令 git tag <name> 用于新建一个标签,默认为 HEAD ,也可以指定一个 commit id
      • git tag -a <tagname> -m "XXX" 可以指定标签信息
      • git tag -s <tagname> -m "XXX" 可以用 PGP签名标签
      • 命令 git tag 可以查看所有标签
  7. 操作标签

    • 如果标签打错了,也可以使用 git tag -d <tagname> 命令进行删除:
      git学习笔记2

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

    • 如果要推送某个标签到远程,使用命令 git push origin <tagname> :
      git学习笔记2
    • 如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除,然后从远程删除,删除命令也是 push 但是要注意格式:
      git学习笔记2
    • 小结
      • 命令 git push origin <tagname> 可以推送一个本地标签
      • 命令 git push origin --tags 可以推送全部未推送过的本地标签
      • 命令 git tag -d <name> 可以删除一个本地标签
      • 命令 git push origin :refs/tags/<tagname> 可以删除一个远程标签