【git篇】git的使用

avatar
作者
筋斗云
阅读量:0

文章目录

1. Git介绍与安装

1. Git简介

Git是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。

集中式(SVN) VS 分布式(git)

集中式版本控制系统,版本库是集中存放在中央服务器的,工作时要先从中央服务器取得最新的版本,完成工作后,再把自己的文件推送给中央服务器。集中式版本控制系统在工作时需要联网

分布式版本控制系统没有“中央服务器”,每个人的电脑上都是一个完整的版本库,所以就不需要联网。

分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了,随便从其他人那里复制一个就可以了。

分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。

2. 下载安装程序

https://git-scm.com/downloads

https://download.tortoisegit.org/tgit/

按默认选项安装即可。安装完成后,在开始菜单里找到“Git”->“Git Bash”,出现命令行窗口的,就说明Git安装成功!

3. 设置用户名和邮箱

$ git config --global user.name "Your Name" $ git config --global user.email "email@example.com" # 示例: # git config --global user.name "jiangxiaonan" # git config --global user.email "xxc111111@163.com" 

因为Git是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和Email地址。

2. Git的基本使用

1. 创建版本库

版本库又名仓库,英文名repository,可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。

$ mkdir git_study $ cd git_study $ pwd /d/Work/Git/git_study 

注意:为了避免遇到各种莫名其妙的问题,请确保目录名(包括父目录)不包含中文。

$ git init Initialized empty Git repository in D:/Work/study_git/.git/ 

此步骤为初始化仓库,同时生成一个.git的隐藏目录。这个目录是Git来跟踪管理版本库的,不要乱改动。

2. 文件管理

1. 提交文件

创建一个.txt的文件,内容可随意写。

$ git add file1.txt 
$ git commit -m "write a file" [master (root-commit) e6fddb0] write a file  1 file changed, 2 insertions(+)  create mode 100644 file01.txt 

git add是告诉git有一个文件添加到了仓库。

git commit是告诉git这个文件正式提交了。-m后面输入的是本次提交的说明,可以输入任意内容,当然最好是有意义的。

说明

使用命令git add <file>,可反复多次使用,添加多个文件;最后可使用命令git commit -m <message>一次性提交。

通过以上命令,即可创建一个仓库并提交文件。

2. 查看状态
$ git status 

可以看到哪些文件修改了,或者新增了等等,就是告诉你当前哪些文件处于什么状态。

3. 查看提交日志

将file01.txt重新修改多次,然后提交仓库。

我这里修改了两次。

git log 

通过命令即可看到每次提交的信息。重点关注commit -m时填写的说明,方便查看每次主要修改了那些内容。

$ git log --pretty=oneline 

此命令可以简化日志的输出。从下往上看,依次显示每次的提交内容,最上面为当前的最新版本。

4. 版本回退

通过日志,可以看出每次提交都会形成一个commit_id,使用以下命令可以回退到之前的版本。

git reset --hard commit_id 

版本回退成功。

$ git reflog 

如果你又不想回退了,想恢复到回退以前,可以使用git reflog查看之前的commit_id是什么,继续使用版本回退的命令返回过去。

注意commit_id没有必要写全,一般写前五六位即可,git会自行判断。

3. 原理解析

1. Git区的划分

workspace:工作区

Index:暂存区

Repository:本地仓库

Remote:远程仓库

可以在工作区中,添加、删除、修改文件等等操作。add实际是将文件保存在暂存区,commit是将文件一次性提交给本地库。所以暂存区和本地仓库(初始化时默认会创建一个master分支)实际都在.git隐藏目录中。

说明:Git跟踪并管理的是修改,而非文件。如果一个文件的修改要想被提交到Repository,必须经过add->commit的顺序。因为工作区的修改不会被提交,只有暂存区的修改才能被提交。

比如我们将file01.txt修改了,然后直接commit

# 修改完之后查看工作区和版本库里面最新版本的区别 $ git diff HEAD -- file01.txt 

2. 撤销修改

分为多种情况:

场景1:如果只是工作区写坏了,想丢弃修改,可以使用以下命令

$ git checkout -- file01.txt 

git checkout -- file命令中的--很重要,没有--,就变成了“切换到另一个分支”的命令。

场景2:如果工作区文件写坏了,并且add到了暂存区,想丢弃修改,可以使用以下命令

$ git reset HEAD file01.txt  $ git checkout -- file01.txt 

用命令git reset HEAD <file>,就回到了场景1,然后按场景1操作。

场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,可以进行版本回退的方法操作,不过前提是没有推送到远程库。

3. 删除文件

场景1:如果你要删除的文件之前已经提交过版本库了,那么可以很轻松得找回来。

$ git checkout -- <file> 

说明:不管是误删,还是修改错了,都可以使用这个命令将文件复原回来。

注意:从来没有被添加到版本库就被删除的文件,是无法恢复的!

场景2:如果你真要删除此文件,可以使用以下命令

# 告诉git要删除文件了 $ git rm test.txt # 再次提交 $ git commit -m "remove test.txt" 

现在,文件就从版本库中被删除了。

4. 分支管理

1. 基本原理

一个仓库本身只有一条分支线。一开始只有一条分支,你的所有提交都会提交到master上,这条线会随着提交的次数增多而越来越长。

如果创建了新的分支,那么会在master的位置新创建一条分支,比如dev,但是分支线还是只有一条。

那么你新的提交就是针对新的分支了,随着提交的增多这条线会越来越长。而master还在原来的位置没有动。

当你将devmaster合并,实际上是将master指针指向当前dev的位置。

2. 创建分支
$ git checkout -b dev  # `git checkout`命令加上`-b`参数表示创建并切换,相当于以下两条命令 $ git branch dev  # 创建分支 $ git checkout dev  # 切换分支 

对于创建分支,还有如下命令可以使用

$ git switch -c dev  # `git switch`命令加上`-c`参数表示创建并切换,相当于以下两条命令 $ git branch dev  # 创建分支 $ git switch dev  # 切换分支 

注意:使用git checkout时区分前面说过的撤销修改git checkout -- <file>.

查看当前分支

$ git branch 

git branch命令会列出所有分支,当前分支前面会标一个*号。

现在我们就可以在dev分支上提交了,而且不会影响到master分支。

比如我们修改了README.md的文件。

切换到master分支发现文件并没有被修改。

3. 合并分支

现在处在master分支,现在我们将dev分支合并上来。再次查看README.md文件,发现是被修改过的。

$ git merge dev 

4. 删除分支

现在master分支和dev分支内容一致了,那么dev分支的使命也就完成了,可以将其删除,当然你也可以继续在上面工作。

$ git branch -d dev 

说明:在实际的工作中,通常会创建多条分支,防止master被频繁修改导致出错的现象,确保过程更安全。

5. 解决冲突

冲突发生在合并分支的时候。

我们新建一个分支feature1,并且修改README.md的内容。

然后提交。

现在切换到master分支同样修改README.md文件内容。并提交。

最后合并feature1分支。

显示合并失败,并指出了是哪个文件。

这时需要手动修改冲突文件的内容。

<<<<<<< HEAD表示当前所处分支的内容。=======为分割线。>>>>>>> feature1表示冲突分支的内容,需要将他们修改为最终需要的内容。

最后重新提交。

git log --graph命令可以看到分支合并图。

$ git log --graph --pretty=oneline --abbrev-commit 

这个时候你可以删除feature1分支,或者继续使用。

6. 分支管理策略

git分支合并时,默认采用Fast forward模式,这种模式下,删除分支后,会丢掉分支信息。

如果要强制禁用Fast forward模式,git会在merge时生成一个新的commit,这样,从分支历史就能看出分支信息。

$ git merge --no-ff -m "merge with no-ff" dev 

合并dev分支,使用--no-ff,表示禁用Fast forward模式。

因为本次合并是新的commit,所以需要加上-m,并把提交的说明填写上去。

3. 远程仓库

1. 添加远程仓库

1.添加公钥

$ ssh-keygen -t ed25519 -C "Gitee SSH Key" # -t key 类型 # -C 注释 

2.创建远程仓库

通常情况下远程仓库名称和本地名称一致,方便区分。

3.关联仓库并提交文件

根据提示,既可以新建本地仓库与远程仓库,也可以使用已有的本地仓库。

$ git remote add origin git@gitee.com:xie_xuchun/study_git.git 

origin是给远程仓库起的名称。

$ git push -u origin "master" 

把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程。

由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送到远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。

$ git push origin master 

说明:当你第一次使用Git的clone或者push命令连接Gitee时,会得到一个警告,这是因为Git使用SSH连接,而SSH连接在第一次验证Gitee服务器的Key时,需要你确认Gitee的Key的指纹信息是否真的来自Gitee的服务器,输入yes回车即可。Git会输出一个警告,告诉你已经把Gitee的Key添加到本机的一个信任列表里了。

2. 删除仓库

在删除仓库之前,我们需要先查看当前仓库的信息。

$ git remote -v 

然后,根据名字删除,比如删除origin:

$ git remote rm origin 

说明:“删除”其实是解除了本地和远程的绑定关系,并不是物理上删除了远程库。

3. 从远程库克隆

之前我们是先有本地库,然后才创建和关联的远程库。现在我们不创建本地库,直接从远程库进行克隆。

1.创建远程库

为了方便查看变化,给他初始化一个readme的文件

2.克隆到本地

$ git clone git@gitee.com:xie_xuchun/we-are-study.git 

说明:Gitee给出的地址不止一个,还可以用https://gitee.com/xie_xuchun/we-are-study.git这样的地址。实际上,Git支持多种协议,默认的git://使用ssh,使用https除了速度慢以外,每次推送都必须输入口令。

4. Bug分支

每个Bug都可以通过创建临时分支来修复。修复后,合并分支,然后即可删除临时分支。

问题?我的dev分支代码还没完成,就创建临时分支,该如何提交?

方法:可以通过stash把当前现场储藏起来,等以后恢复现场后再继续工作。

$ git stash 

假定我们现在要在master分支修复代码,这时就可以在master分支上创建临时分支。

$ git checkout master $ git switch -c issue-101 
# 然后进行代码修复 $ git add readme.txt $ git commit -m "update bug" 

然后切换到master分支进行合并,再删除bug分支。

$ git switch master $ git merge --no-ff -m "merge bug" issue-101 

现在bug修复完成了,我们又可以回到dev分支继续干活了。

$ git switch dev $ git status 

此刻dev分支时干净的,因为我们之前将现场储藏了起来,可以通过

$ git stash list 

查看。可以发现有一个隐藏。

现在我们就可以恢复现场了。

$ git stash apply  # 或者使用 $ git stash pop  # 两个区别就是恢复完成之后是否删除stash内容,使用后者会进行删除。 

当然,你如果有多次stash,可以恢复指定的stash。

$ git stash apply stash@{0} 

思考:刚才是在新建的临时分支上修改的bug,但是我当前工作的分支并没有这个修改,如果重新写一遍就是重复造轮子了,怎样让这些修改在dev分支上重放?

这时,我们可以查看之前新建分支上提交的commit_id,将他重放到dev上。

说明:在重放之前,需要保持储藏的状态,重放完才可以取消储藏。

$ git cherry-pick 4c805e2 

git给dev分支自动做了一次提交。使用了cherry-pick,就不需要在dev分支重复修改bug了。

5. feature分支

实际的工作中,各种新功能是非常多了,但是我们又不希望新的功能将主分支搞乱,这个时候对于新的功能需求,就可以新建一个feature分支,在上面开发,完成后合并,最后删除该feature分支。

$ git switch -c feature $ git add readme.txt $ git commit -m "new" 

一切顺利的话,就可以切换到dev合并代码了

$ git switch dev 

但是这时出了意外,新功能不需要了,那么直接删除feature分支就可以。

$ git branch -D feature 

说明:如果我们合并过了,可以使用-d,但是这种没有合并就删除的情况需要使用-D进行强制删除。

6. 标签管理

1. 创建标签

在Git中打标签非常简单,首先,切换到需要打标签的分支上,比如dev分支:

$ git switch dev 

然后在当前分支打标签

$ git tag v1.0 

默认标签是搭载最新提交的commit上的。如果要对历史某一次提交打标签,需要找到历史的某次提交commit_id,然后打标签。

$ git tag v0.9 db6707e 

还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字。

git tag -a v0.1 -m "This is v0.1" f8d7e15 

查看标签

$ git tag  $ git show v0.9 

git tag列出所有的标签。git show v0.9,列出某一个tag的详细信息。

2. 操作标签

本地删除标签

$ git tag -d v0.1 

创建的标签只存储在本地,不会自动推送到远程。可以安全删除。

远程推送标签

如果要推送某个标签到远程,使用命令git push origin <tagname>

$ git push origin v0.9 

或者,一次性推送全部未推送到远程的本地标签:

$ git push origin --tags 

远程删除标签

如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:

$ git tag -d v0.9 

然后,从远程删除。格式如下:

$ git push origin :refs/tags/v0.9 

4. 多人协作

1. 查看分支

当从远程仓库克隆时,Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称时origin。

要是看远程仓库的信息,用

$ git remote -v 

-v参数显示更详细的信息。

2. 推送分支

推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程仓库对应的远程分支上:

$ git push origin master  $ git push origin dev 

masterdev为指定的分支。一般情况下,和其他人有协作开发的分支需要推送远程仓库,某些自己定义的分支可以不用推送。

说明:即使远程仓库当前没有dev分支,按照这样的方式推送会自动创建dev分支

3. 抓取分支

默认情况下,其他人从远程库clone时,只能看到本地的master分支。

git clone git@gitee.com:xie_xuchun/we-are-study.git 

如果你们要在dev分支上合作开发,就需要先建立dev分支的关系。

$ git checkout -b dev origin/dev 

现在,其他人就可以在dev分支上修改,然后进行提交等等操作,进行协作开发了。

如果远程仓库的代码比本地代码更新,这时候git push会产生冲突,从而导致推送失败,这时需要先git pull,在本地解决完冲突之后再推送。

如果在git pull的过程中有报错

$ git pull There is no tracking information for the current branch. Please specify which branch you want to merge with. See git-pull(1) for details.      git pull <remote> <branch>  If you wish to set tracking information for this branch you can do so with:      git branch --set-upstream-to=origin/<branch> dev 

原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接:

$ git branch --set-upstream-to=origin/dev dev 

4. 小结

多人协作的工作模式通常是这样

首先,可以试图用git push origin <branch-name>推送自己的修改;

如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;

如果合并有冲突,则解决冲突,并在本地提交;

没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!

如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>

这就是多人协作的工作模式。

5. 扩展

1. 如何让Git显示颜色

$ git config --global color.ui true 

2. 忽略特殊文件

有些时候,你必须把某些文件放到Git目录中,但又不能提交他们,比如保存了数据库密码的配置文件等等。每次git status都会显示Untracked files ...。这个问题解决起来很简单,在Git工作区的根目录下创建一个特殊的.gitignore文件。

注意:.gitignre文件本身应该提交给Git管理,这样可以确保所有人在同一项目下使用相同的.gitigore文件

示例:

# Compiled class file *.class  # Log file *.log  # BlueJ files *.ctxt  # Mobile Tools for Java (J2ME) .mtj.tmp/  # Package Files # *.jar *.war *.nar *.ear *.zip *.tar.gz *.rar  # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* replay_pid* 

示例文件:https://github.com/github/gitignore

忽略文件的原则是:

  1. 忽略操作系统自动生成的文件,比如缩略图等。
  2. 忽略编译生成的中间文件、可执行文件等,比如java编译产生的.class文件。
  3. 忽略你自己带有敏感信息的配置文件,比如存放口令的配置文件。

如果你想添加某些文件,但是发现添加不了,可以排查是不是这种类型的文件被忽略掉了。比如添加了App.class文件。

$ git check-ignore -v App.class .gitignore:2:*.class    App.class 

发现是因为.gitignore的第二行.class给忽略掉了。

如果确实要添加,可以这样改造.gitignore文件。

# Compiled class file *.class  # Log file *.log  # BlueJ files *.ctxt  # Mobile Tools for Java (J2ME) .mtj.tmp/  # Package Files # *.jar *.war *.nar *.ear *.zip *.tar.gz *.rar  # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* replay_pid*  # 不排除.gitignore和App.class: !.gitignore !App.class 

使用!+文件名的方式排除掉忽略。

这样就可以正常添加了。

3. 配置别名

对于经常使用,而写起来难度较大的命令,我们可以配置别名

$ git config --global alias.st status  $ git config --global alias.co checkout $ git config --global alias.ci commit $ git config --global alias.br branch 

配置完别名之后,以后的提交就可以这样写

$ git ci -m "bala bala bala..." 

甚至你还可以这样写,将你需要起别名长命令都可以写进来。

git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit" 

--global参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有用。当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig中:

如果不使用--global,那么只是对当前仓库生效,每个仓库的Git配置文件都放在.git/config文件中

对于大多数情况,使用别名的方式更好,推荐。

4. 如何参与一个开源项目

比如bootstraps项目。https://github.com/twbs/bootstrap

点“Fork”就在自己的账号下克隆了一个bootstrap仓库,然后,从自己的账号下clone:

这个时候就可以拉取到本地进行修改提交。注意修改提交还是在自己的仓库。

之后可以通过pull request推送给作者,由作者选择是否使用代码。

6. 搭建Git服务器

搭建Git服务器需要准备一台运行Linux的机器,强烈推荐用Ubuntu或Debian,这样,通过几条简单的apt命令就可以完成安装。

以下命令如果是非root用户执行需要加sudo

第一步,安装git

$ yum install git 

第二步,创建一个git用户,用来运行git服务:

$ adduser git 

第三步,创建证书登录:

收集所有需要登陆的用户的公钥,就是他们自己的id_rsa.pub文件,把所有公钥导入到/home/git/.ssh/authorized_keys文件里,一行一个。
在这里插入图片描述

第四步,初始化Git仓库:

先选定一个目录作为Git仓库,假定是/srv/sample.git,在/srv目录下输入命令:

$ git init --bare sample.git 

Git就会创建一个裸仓库,裸仓库没有工作区,因为服务器上的Git仓库纯粹是为了共享,所以不让用户直接登录到服务器上去改工作区,并且服务器上的Git仓库通常以.git结尾

然后,把owner改为git

$ chown -R git:git sample.git 

第五步,禁用shell登录:

出于安全考虑,第二步创建的git用户不允许登录shell,这可以通过编辑/etc/passwd文件完成。找到类似下面的一行:

git:x:1001:1001:,,,:/home/git:/bin/bash  改为  git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell 

这样,git用户可以正常通过ssh使用git,但无法登录shell,因为我们为git用户指定的git-shell每次一登录就自动退出。

第六步,克隆远程仓库:

现在,可以通过git clone命令克隆远程仓库了,在各自的电脑上运行:

$ git clone git@server:/srv/sample.git  # git cloine git@11.0.1.10:/srv/sample.git 

完成。

说明

要方便管理公钥,用Gitosis;

要像SVN那样变态地控制权限,用Gitolite。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!