T.C

Git基础概念与操作

设计哲学

If you’re not distributed, you are not worth using, it’s that simple. If you perform badly, you are not worth using, it is that simple. And if you cannot guarantee that the stuff I put into an SCM comes out exactly the same, you are not worth using. Quite frankly, that pretty much took care of everything out there.

Linus · Torvalds @ Google Talk 2007

概念介绍

Git一般有三种状态:

除以上三种状态外,还有一种已推送状态(Pushed),即将本地的修改推送到远程仓库。

Git项目一般有三个工作区域:

除以上的三个工作区域外,为了方便团队开发会维护一个远程仓库(remote repository)。

基本流程

sequenceDiagram participant w as Working Directory participant s as Staging Area participant l as Local Repository participant r as Remote Repository w->>s: git add <file>... s->>w: git reset HEAD <file>... note over w,s: Keep changes s->>w: git checkout -- <file>... note over w,s: Discard changes s->>l: git commit alt add more staged files s->>l: git commit --amend end l->>r: git push <remote> <branch> r->>l: git fetch <remote> <branch> r->>l: git pull <remote> <branch> r->>w: git clone <repo>

基础命令

获取Git仓库

提交更改

文件操作

查看历史

撤销操作

远程仓库

标签管理

分支管理

常用操作

merge和rebase操作

merge合并分支

basic-branch-6.png

假如要合并iss53到master,只需要切换到master分支,然后进行merge操作。

$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html |    1 +
1 file changed, 1 insertion(+)

basic-merging-1.png

此时Git会使用两个分支的末端所指的快照(C4 和 C5)以及这两个分支的工作祖先(C2),做一个简单的三方合并。做了一个新的快照并且自动创建一个新的提交指向它。 这个被称作一次合并提交,它的特别之处在于他有不止一个父提交。

basic-merging-2.png

合并完成之后就可以删除iss53分支了。

$ git branch -d iss53

rebase合并分支

basic-rebase-1.png

如果要合并C3C4,可以提取在C4中引入的补丁和修改,然后在C3的基础上应用一次,这种操作在Git中叫rebase。rebase命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样。

$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command

它的原理是首先找到这两个分支(即当前分支 experiment、rebase操作的目标基底分支 master)的最近共同祖先 C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件,然后将当前分支指向目标基底 C3, 最后以此将之前另存为临时文件的修改依序应用。

basic-rebase-3.png

现在回到 master 分支,进行一次快进合并。

$ git checkout master
$ git merge experiment

basic-rebase-4.png

区别

这两种整合方法的最终结果没有任何区别,但是rebase使得提交历史更加整洁,因为rebase操作的实质是丢弃了一些现有的提交。一般我们这样做的目的是为了确保在向远程分支推送时能保持提交历史的整洁。 在这种情况下,首先在自己的分支里进行开发,当开发完成时先将代码rebase到 origin/master 上,然后再向主项目提交修改。 这样的话,该项目的维护者就不再需要进行整合工作,只需要快进合并便可。

请注意,无论是通过rebase,还是通过merge,整合的最终结果所指向的快照始终是一样的,只不过提交历史不同罢了。 rebase是将一系列提交按照原有次序依次应用到另一分支上,而merge是把最终结果合在一起。

原则

只对尚未推送或分享给别人的本地修改执行变基操作清理历史,从不对已推送至别处的提交执行变基操作。

合并分支时解决冲突

如果在不同分支中,对同一个文件的同一个部分做了不同的修改,Git合并的时候就会产生冲突,此时需要手动来解决冲突。比如合并iss53假如有冲突会有这样的提示:

$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

此时Git虽然做了部分合并,但是没有自动创建一个新的合并提交,并且留下了有冲突的文件标记为unmerged等我们自己解决冲突。

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)

    both modified:      index.html

no changes added to commit (use "git add" and/or "git commit -a")

出现冲突的文件会包含一些冲突标记:

<<<<<<< HEAD:index.html
<div id="footer">contact : [email protected]</div>
=======
<div id="footer">
 please contact us at [email protected]
</div>
>>>>>>> iss53:index.html

=======会区分不同修改,需要手动选择保留哪个分支的修改,然后删除这些标记。解决了所有的冲突之后,对每个文件使用git add命令将其暂存,一旦暂存这些原本有冲突的文件,Git就会将它们标记为冲突已解决。在此期间可以使用git status来查看文件状态。全部暂存完之后就可以用git commit来完成合并提交。

stash工具

Git提供了一个储存自己当前工作目录中未提交的更改的工具,叫做stash。比如当工作一段时间之后需要切换到另外一个分支做别的事情,但是又不想提交当前分支做了一半的更改,于是就可以将当前的更改使用git stash命令储存起来,然后去另外一个分支工作,最后切回这个分支,再取出之前储存的做了一半的更改。

搜索

Git提供了两个有用的工具来快速地从它的数据库中浏览代码和提交。

Git Grep

git grep命令有一些的优点。 第一就是速度非常快,第二是你不仅仅可以可以搜索工作目录,还可以搜索任意的Git树。

Git日志搜索

一般用来查看某一项是什么时候存在或者什么时候引入的。

GitWeb服务

Git自带了一个简单的CGI脚本,可以启动一个Server用来查看本地的Git仓库。如果既不想用命令行查看又不想自己部署一套复杂的Web服务,可以使用这个,非常方便。

LFS插件

安装

然后执行git lfs install开启LFS功能。

命令:

参考资料