git使用教程

来源:互联网 发布:mac搜狗五笔输入法 编辑:程序博客网 时间:2024/06/08 19:52

git使用教程

标签(空格分隔): git 教程 操作 命令


基本概念:

Git 是一款免费、开源的分布式版本控制系统,他是著名的 Linux 发明者 Linus Torvalds 开发的。

GitHub 主要提供基于 git 的版本托管服务。也就是说现在 GitHub 上托管的所有项目代码都是基于 Git 来进行版本控制的,所以 Git 只是 GitHub 上用来管理项目的一个工具。

Git与其它版本控制工具的区别?
Git与其它版本控制系统相比,Git跟踪并管理的是文件修改,而不是文件,它自始至终跟踪的都是文件内容的变更(不包括二进制流的文件,git只能跟踪这些文件的大小)。Git支持多种协议,包括Https,但通过ssh支持的原生git协议速度最快

什么是工作区?
本地存放需要提交文件变更的目录,其实就是开始执行git init命令的目录。

什么是版本库?
工作区中有一个隐藏目录叫做.git,这个不算工作区,这是Git的版本库。版本库中最重要的就是暂存区(stage),还有Git为我们创建的第一个分支(master),以及指向当前分支的指针(HEAD)。

什么是暂存区?
暂存区英文名叫做stage(或者也叫做index),对应于.git目录下的index文件。顾名思义,就是先将要提交的文件修改临时存放到该地方,然后再将其中的临时文件统一提交到本地分支(local repository),最后推送到远程仓库(remote repository)。

话不多说,实践才是硬道理。

一次具体的操作流程

(1)创建一个新文件,并用git status命令查看当前工作状态:
没有被git跟踪的新文件
解释:有新文件没有被git跟踪到(Untracked files),下面我们需要让git来跟踪到该文件。

(2)执行git add命令,将该文件添加到暂存区(stage),此时git就可以跟踪到该文件了,用git status查看此时的工作状态:
git等待被提交
解释:该文件等待被提交(commit),证明该文件修改已经存在于暂存区了。

(3)执行git commit -m “xxx”命令,来将暂存区中的文件修改添加到本地分支上,用git status来查看当前的工作状态:
git commit
解释:当前分支已经提前远程master分支一个提交了,证明该文件修改已经提交到了当前分支上。

(4)执行git push origin master,将本次提交推送到远程仓库的master分支下,用git status来查看当前的工作状态:
推送到远程仓库
解释:此时本地分支已经和远程分支同步了,没有文件更改等待被提交。

以上操作,可以用一张图来演绎:
工作目录、暂存区到本地分支

上面,我们演示了一次具体的文件变更从本地提交到远程仓库的流程,想必大家现在应该有很多疑问,master是什么?branch是什么?origin是什么意思?add,commit,push分别是什么意思?下面我就一一来解释。

文件修改从工作区到当前分支

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

下面是提交代码的整个流程:
第一步:本地文件有修改,使用git add命令将文件修改添加到暂存区中,此时使用git status命令查看,提示的信息是有文件修改等待被提交(Changes to be committed),Git实际上是为我们做了如下的操作:

将文件修改添加到暂存区中

第二步:使用git commit命令将文本修改提交到当前分支,此时使用git status命令查看,提示的信息是本地没有文件变更等待被提交(nothing to commit, working tree clean),Git实际上是为我们做了如下操作:

文件修改从暂存区提交到本地分支

日常开发中,不可能保证每次文件的修改都是准确的。此时,我们就需要撤销掉不想要的文件修改。这里分两种情况,一种是撤销工作目录中的文件修改,另一种是撤销已经添加到暂存区后的文件修改。

第一种,撤销工作目录中的文件修改,这里又细分为两种场景:

第一种:文件修改还没有添加到暂存区中,此时执行git checkout命令将撤销修改回到该文件上一次git commit后的状态;
第二种:文件修改已经添加到了暂存区中,此时又做了新的修改,此时执行git checkout命令,将会撤销文件修改回到该文件上一次执行git add后的状态。

第二种,撤销暂存区中的文件修改:

执行git reset HEAD “filename”将该文件修改移除暂存区,使之回到工作目录中,再执行git checkout命令将文件修改给撤销到上一次执行git commit后的状态。

那么你又该问了,假如这个文件修改已经提交到本地分支上,又该如何撤销呢?
此时已经产生了一个新的commit-hash,我们就只能将代码回滚到上一个commit-hash状态下了,版本回退后面会重点进行讲解。需要先执行git log命令找到上一次提交到当前分支的commit-hash,再执行git reset –hard “commit-hash”命令回退到上一次执行git commit后的状态,或者直接执行git reset –hard HEAD^,意味着将HEAD指针回退一个commit,注意git会丢弃掉你不需要的commit-hash(也就是最新的一次commit-hash)。

删除文件(git rm和rm命令有什么区别)
git rm命令:若对已经被git跟踪的文件,执行了git rm命令,此时git仍然可以追踪到该文件的修改,在下一次执行git commit时,会自动将删除该文件的操作提交上去;
rm命令:仅仅是删除了物理文件,没有从git记录中删除,在下次我们执行git commit操作时,则不会将删除该文件的操作提交上去。(其实rm就是背着git偷偷地将文件给删除了,git只能通过比较前后文件的差异来知晓)

以上,就是我们在工作目录和当前分支中来管理文件修改的相关操作。

分支管理

在日常开发中,需要与别人一同协作,此时光有一条分支是远远不够的,所以我们要创建多个分支。先说说什么是分支?Git把每次提交串成一条时间线,这条时间线就是一条分支。目前来说,我们的本地仓库中只有一条分支,那就是Git为我们默认创建的主分支master(其实是有一个master指针指向该分支),Git还会为我们创建一个HEAD指针,它指向的是master指针。

git默认为我们创建的master分支和HEAD指针:
git默认为我们创建的master分支和HEAD指针

分支相关的操作命令:

创建分支

git branch “branch-name”:新建一个名为branch-name的分支,新创建了一个branch-name的指针指向当前分支;
git checkout “branch-name”:切换到名为branch-name的分支上,将HEAD指针指向branch-name指针;
git checkout -b “branch-name”:相当于git branch + git checkout,为我们创建了名为branch-name的分支,并切换到该分支上。

查看分支

git branch:用于查看本地有哪些分支,以及当前处于哪个分支上(前面带*);
git branch -a:用于查看本地和远程仓库都有哪些分支,-a是list的意思。

删除分支:

git branch -d “branch-name”:删除名为branch-name的分支,即删除指向该分支的指针;
git branch -D “branch-name”:强制删除名为branch-name的分支,当分支上有文件修改尚未合并时,会提示删除失败,此时需要强制删除。

推送分支:

当所有的文件修改已经提交到当前分支上了,此时我们就需要将这些文件修改推送到远程仓库了,需要执行git push [远程仓库名]  [本地分支]:[远程分支],将本地分支的文件修改推送到远程仓库的对应分支下。

版本回退(一般很少用)

随着需求的变更,可能我们最近写的代码不需要了,需要将代码回滚到某个时间点,此时我们该怎么做呢?
需要执行版本回退相关的相关命令,使工作目录回退到以前某次执行git commit后的状态,git会让HEAD指针指向我们想要的那个commit-hash。具体的操作命令是用git log命令查找到对应commit-hash,再执行git reset –hard “commit-hash”。

版本回退的原理

你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一条分支。一开始的时候,只有一条主分支,Git用master指针指向最新的提交,再用HEAD指针指向master,就能确定当前分支,以及当前分支的提交点:
HEAD指向master分支

每次提交,master分支都会向前移动一步,这样随着你的不断提交,master分支的线也会越来越长,当我们创建新的分支并执行切换时(git checkout -b dev)时,Git新建了一个指针dev,指向master当前相同的提交,再把HEAD指向dev分支,就表示当前分支在dev上:
HEAD指向dev分支

现在对工作区的修改和提交就是针对于dev分支了,比如新提交一次,dev分支就向前移动一步,而mster分支保持不动:
dev分支移动

所以HEAD当前指向哪个分支,就是我们当前所在分支,当我们执行版本回退时,相当于把HEAD指针在当前分支上向前移动,但是回退到的commit-hash以后的提交就会被丢弃,最终被git垃圾处理机制给回收
版本回退

另一种版本回退的策略

执行git revert “commit-hash”命令,此时git会为我们创建一个新的commit-hash,该commit-hash对应的工作状态对应于我们想要的那个commit状态,但是git确不会丢弃我们回退到的commit-hash以后的提交。
git revert "commit-hash"

合并分支

在我们日常开发中,经常会需要用到分支合并的场景,此时我们就需要用到git merge命令。假如我们想把dev分支上的文件修改合并到master分支上,需要先切换到master分支上(git checkout master),然后执行合并dev分支(git merge dev)。Git此时会为这种操作执行了一种快进方式(fast forward),就是将指向dev指针的HEAD指针指向master,再将dev分支上与master分支上不同的文件修改合并(将dev上与master上不同的commit-hash合并),再将HEAD指针指向master最新的提交。
合并分支

所以Git合并分支也很快,就改改指针,工作区内容也不用变。

解决冲突:
当执行git merge “branch-name”时有时会出现conflict,这是由于两个分支在合并过程中发现对文件的相同内容做了不同的修改而造成的,此时我们就需要解决冲突。
HEAD代表当前分支上的文件修改,dev代表dev上的文件修改,看哪种文件修改是你想要的,则删除另外一个文件修改,此时git对你执行的命令的策略是创建一个新的提交来保存你最新的文件修改(可以看成将两根绳绑起来会出现一个新节点)。
解决冲突的策略

管理本地仓库

初始化本地仓库

git init:初始化git仓库,此时工作目录下会多出一个.git目录。

clone远程仓库到本地

git clone “git仓库的URL”:克隆远程仓库到本地,这个时候该项目本身已经是git仓库了,不需要再执行git init命令,而且已经关联好了远程仓库,我们只需要在这个项目中修改文件,然后直接进行commit和push操作。

git status:查看本地仓库当前的状态;
git log:可以查看当前分支上所有的commit记录;
git branch:可以查看本地仓库有哪些分支;
git branch -a:查看本地仓库和远程仓库一共有哪些分支;
git diff:可以比较两个文件修改之间的差异。

diff命令

diff命令算是很常用的,使用场景是我们经常在做代码改动,可以实时比较代码改动:
git diff:默认是比较当前文件和暂存区文件的差异;
git diff “commit-hash1” “commit-hash2”:比较两次提交之前的差异,commit-hash2提交相比较于commit-hash1提交做了哪些更改;
git diff “branch1” “branch2”:比较两个分支的差异,branch2上的文件相比于branch1做了哪些改动;
git diff –cached:比较暂存区和当前分支的差异;
git diff HEAD:比较工作目录与当前分支的差异。

blame命令

如果你想要看看某一个文件的相关历史记录,可以使用git blame 命令,可以很清楚的了解每行代码是谁开发的。 如git blame filename –date short
效果图:git blame效果

临时存储修改,保存工作现场

当你有一个bug任务,你想创建一个issue-01分支来修复它,但是你当前正在dev分支上进行的工作还没有完成,此时又不能提交,若直接切换分支,可能会发生文件修改被覆盖的情况,Git提供了一个stash功能,可以把当前工作现场“储存”起来,等以后可以恢复现场。
git stash:将当前工作现场存储到缓存栈中;
git stash list:查看当前有缓存栈中存储了哪些“现场”,是根据你commit-hash的前后来排序的;
git stash clear:清除缓存栈;
git stash apply:可以恢复现场,但是该现场并不会从缓存栈删除,需要再次执行git stash drop来删除;
git stash pop:直接将“现场”从缓存栈中倒出来恢复现场,不需要再删除。

管理远程仓库

如何新建远程仓库,这里我就不重复造轮子了。创建远程仓库
git remote add origin git@server-name:path/repo-name.git:给本地仓库关联远程仓库,并给它起代号为origin,为什么要起名呢,因为有可能本地仓库对应着不止一个远程仓库,后面方便直接根据该代号来将本地仓库的提交推送到远程仓库,不需要执行全名。
git remote -v:查看本地工作目录关联着哪些远程仓库;
git push -u [远程仓库名]   [本地分支]:[远程分支]:将本地分支上的提交推送到远程分支,并将本地分支与远程仓库下该分支关联,以后推送的时候可以直接执行git push命令,不用再指定远程仓库名。
git push [远程仓库名] [本地分支]:[远程分支]:作用同上,但没有将本地分支与远程分支关联起来;
git push origin “branch-name”:作用同上;
git push [远程仓库名]  :[分支名]:删除远程分支

创建标签

git tag “tag-name”:在当前代码状态下新建了名为tag-name的标签,输入git tag就可以查看本地仓库有哪些tag;
git tag -d “tag-name”:删除本地名为tag-name的标签;
git tag:查看本地仓库的tag列表;
git checkout “tag-name”:切换到tag字为tag-name的标签的工作状态下;
git reset –hard “tag-name”:将本地仓库回滚到名为tag-name的标签的工作状态下;

要将本地分支推送到远程仓库中,需要使用跟推送分支相同的命令格式,git push [远程仓库名]  [本地标签名] :refs/tags/[远程标签名]
git push origin “本地tag-name”:refs/tags/”tag-name”:推送本地分支到远程仓库中;
git push origin :refs/tag/”tag-name”:删除远程仓库中的分支。

补充

git rebase与git merge哪个好,这里就不重复造轮子了,时间门:git rebase实现原理

设置全局的邮箱和姓名

git config –global user.name “xxx”
git config –global user.email “xxxx@163.com”

设置当前仓库的邮箱和姓名,仅对当前仓库有效

git config user.name “xxx”
git config user.email “xxxx@163.com”

alias,给git操作命令起别名

git config –global alias.co checkout :git co代替git checkout命令;
git config –global alias.ci commit:git ci代替git commit命令;
git config –global alias.st status:git st代替git status命令;
git config –global alias.br branch:git br代替git branch命令;
以上操作,也可以直接修改git的本地用户的配置文件,在~/.gitconfig文件中修改。

特别炫酷的命令:
git log –graph –pretty=format:’%Cred%h%Creset -%C(yellow)% d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset’ –abbrev-commit –date=relative:可以以图表的方式观察所有的commit列表。
效果如下:
以图表的方式观察所有的commit列表

0 0
原创粉丝点击