1. git常用命令详解

一灰灰blog基本功系列Git约 9152 字大约 31 分钟

相信每一个开发者都使用过或者说是听过git,比如大名鼎鼎的"全球最大同性交友网站--GitHub"就是利用git这一分布式版本控制系统来管理大家的项目的;

一般公司内的代码管理常见有两种,一个是SVN,一个是GIT;当然后者更常见,作为一个码农,如果不想被身边的小伙伴鄙视or吐槽,掌握基本的git操作技巧属于必备的生存技能了,本文不会带你成为git专家,更多的是介绍作为一个开发者,在日常的工作中,经常使用git命令以及必备的git技巧

本文主要包含以下知识点

  • 环境安装,配置
  • 获取代吗,提交本地修改并推送
  • 分支创建、切换、删除,合并
  • 标签的使用姿势
  • 如何回滚,暂存
  • 代码冲突怎么办
  • 手误提交了敏感信息,如何彻底删除

I. 基本篇

为方便国内的小伙伴正常使用,我们以Gitee作为演示的git服务器,关于git的基本使用姿势与github并无差别

0. Git安装

首先我们得安装git环境,下面简单介绍一下Win/Linux/Mac三个操作系统下的安装姿势

a. win

在官网https://git-scm.com/download/winopen in new window下载安装包,完成windows平台的安装

完毕之后,找到git bash或者是git terminal,打开一个类似终端的窗口,输入git --version命令,如果正常返回,则表示ok

b. linux

linux环境下,通常可以借助apt-get or yum来安装,如

## ubuntu
sudo apt-get install git

## yum
sudo yum install git

对于其他的linux/unix操作系统,具体的安装命令可以查看: Download for Linux and Unixopen in new window

c. mac

Mac自带git,因此完全是可以开箱即用;当然如果我希望体验最新的git,推荐通过homebrew来安装

sudo brew install git

1. 基本配置

git安装完毕之后,需要配置我们的ssh密钥,通过密钥来实现与git服务器之间的校验(避免每次都输入用户名/密码,而且安全性更高)

a. 判断是否存在

首先到根目录确定是否已经有了密钥

# 查看文件夹下的资源
# 如果目录 .ssh 不存在,or目录下为空,则表示我们需要生成密钥
$ ls ~/.ssh

b. 生成密钥

生成密钥: 输入ssh-keygen,并一直回车

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/deploy/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/deploy/.ssh/id_rsa.
Your public key has been saved in /home/deploy/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:IxeVFUFw1y/ZIE0xwh9E8UJMlxwsYwwOp5m2yy7FANI deploy@localhost
The key's randomart image is:
+---[RSA 2048]----+
|    .    .oOXX&=+|
|   . E   .O.oO=B.|
|    . . .= ..o+=o|
|       ....   +.o|
|      . S.     . |
|       o.+.      |
|        .o       |
|       ..        |
|        ..       |
+----[SHA256]-----+

接下来在~/.ssh目录下将可以看到id_rsaid_rsa.pub两个文件,接着我们需要将id_rsa.pub的内容,复制到gitee上,用于后续的git交互鉴权

c. 配置公钥

查看公钥内容

$ cat id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDIK4Skx1ZKYBlKbO5dhCpTbknUEXhiSiOtB+PSnbaQx+ZwVK+Lz3EVs3qj9qotos7kmj6CbcZDbbSVKbCM6ChYBR9k81TgB4q1CxpP7mCAe4Z2m2gAHv+POnsyXzWtvWm4E3FXliJz9/1fWRCcS+iBIyjmZcab8nvt8RqPiPL1zmW72EcyRhckNvFItiHp3aukWhF/4DUOwvjY/ms9QM7nKkZaA2uXc+Z9K4QJCRZ1vIGEqqgKQnsXtpRQXNPaaldaELo4tyzOJLv6JWJ64qEMqtrRWjpXSZOFO2QCts/bWCITwfkllLTlj+i+rV9yysPrSUbuXlTf4ZMBOWWvp/nB yihuihuiyi@gmail.com

进入gitee的ssh公钥添加页面: Gitee SSH公钥配置open in new window

d. 测试

上面的密钥作为测试密钥,写完本篇文章的时候已经删除掉了,建议大家使用自己的账号进行测试

然后开始测试我们的配置是否ok,借助ssh -T git@gitee.com, 使用github的小伙伴,这个命令改成 ssh -T git@github.com

$ ssh -T git@gitee.com
The authenticity of host 'gitee.com (212.64.62.174)' can't be established.
ECDSA key fingerprint is SHA256:FQGC9Kn/eye1W8icdBgrQp+KkGYoFgbVr17bmjey0Wc.
ECDSA key fingerprint is MD5:27:e5:d3:f7:2a:9e:eb:6c:93:cd:1f:c1:47:a3:54:b1.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'gitee.com,212.64.62.174' (ECDSA) to the list of known hosts.
Hi 一灰灰Blog! You've successfully authenticated, but GITEE.COM does not provide shell access.

2. 创建or同步项目

在开始之前,推荐全局配置用户名和邮箱

git config --global user.name "一灰灰Blog"
git config --global user.email "bangzewu@126.com"

接下来我们开始进入正文(是的,前面都是开胃菜,完全可以跳过),一般来说,我们会有下面三种case,分别说明

a. 从0到1创建新项目

在gitee上创建一个空的仓库,步骤如下图的1,2,3,4

接下来在你自己的机器上,开始创建项目

mkdir git-study
cd git-study
git init
touch README.md
git add README.md
git commit -m 'first commit'
git remote add origin https://gitee.com/liuyueyi/git-study.git
git push -u origin master

b. clone已有项目

clone一个已有的项目可能更加常见(毕竟实际的工作中,享受创建项目的人比较是少数)

git clone https://gitee.com/liuyueyi/git-study.git
cd git-study
echo 'hello git' 1> README.md
git add .
git commit -m 'first modify'
git push -u origin master

c. 已有项目关联

我本地有一个项目,gitee上有一个非空的仓库,我希望将这两个项目关联起来,可以如下操作(这个过程和第一个其实差不多)

# 在上面的项目基础上进行操作
rm -rf .git

git init
git remote add origin https://gitee.com/liuyueyi/git-study.git
# 本地创建master分支(关于分支的创建后面有介绍)
git checkout master
# 同步最新的代码
git pull 
echo 'second modify' 1> README.md
git add README.md
git commit -m 'second modify'
git push

d. 小结

创建git项目的三种方式

  • 从0到1创建:
    # 初始化git
    git init
    # 与远程关联
    git remote add origin https://gitee.com/liuyueyi/git-study.git
    # 本地做一些修改
    ...
    # 提交
    git push -u origin master
    
  • clone:
    git clone https://gitee.com/liuyueyi/git-study.git
    # 本地做一些修改
    ...
    # 提交
    git push
    
  • 已有项目:
    git init
    git remote add origin https://gitee.com/liuyueyi/git-study.git
    # 同步最新代码
    git checkout master
    git pull 
    # 本地做一些修改
    ...
    # 提交
    git push
    

3. 修改提交

接下来进入我们日常工作中,接触频率最高的几个操作,提交本地修改并推送到服务器

a. 基本操作

首先我们新增一个文件,并修改README.mdopen in new window

echo 'add new file' 1> new.txt
echo 'some new code' 1> README.md

在我们提交之前,先查看一下当前的状态,可以知道我们有哪些修改,有哪些需要提交

git status

上面只是给出了修改or新增or删除的文件,但是并不知道修改了什么,这个时候可以借助diff来查看

git diff

接下来确认没有问题,希望将修改的内容提交给服务器

# 将README.md的修改,添加到暂存区
git add README.md

# 如果是希望将所有的改动都添加到暂存区,可以如下使用
git add .

使用git commit指明这次提交的说明

git commit -m '修改并提交'

推送改动

# 精确指定推送到哪个分支
git push -u origin master
# 当本地分支与远程分支建立过绑定关系之后(如上面的操作),则可以省略后面的参数,直接如下操作即可
git push

b. 小结

这一小节的内容虽然简单,但是在实际的工作中,基本上100%会出现,所以这一小结的所有内容都属于必须熟练掌握的知识点

  • 查看本地改动: git status
  • 将本地修改提交到暂存区: git add
  • 提交commit信息: git commit -m '这次提交的详细说明'
  • 推送暂存区内容: git push or git push -u origin master

4. 回退

在git的使用过程中,不太可能总是一帆风顺,有些时候发现提交了错误的请求到暂存区了,也有可能我需要回滚到之前的某个版本,那么可以怎么处理呢?

a. 工作区与暂存区

这一小节属于扩展,不了解这两个概念不影响你的日常操作,但是了解之后可能更有助于理解add/commit的作用

工作区

可以简单的理解为我们的项目目录,比如在我们的项目中添加、修改or删除文件,这些都是工作区的操作

暂存区

通过git add可以将工作区的变动,提交到暂存区

注意:如果此时再次修改已经提交到暂存区的文件,那么新的变动依然是在工作区,只有再次git add之后,变动才会同步到暂存区

本地分支

通过git commit将暂存区的变动,提交到当前分支

注意:提交到分支之后,工作区就变得干净了,但是本地的分支会领先服务器,通常这时候建议将本地变动通过git push同步到服务器

b. 版本回退

在我们的git操作历史中,可能有很多次提交,可以通过git log来查看历史日志

git log

在历史的提交版本中,当我希望回到某个版本时,借助git reset --hard/soft 版本号来实现

git reset --hard 72920bfd579ada7e62ceed2c675bce733e804433

请注意,上面的 --hard 回滚到指定的版本,且会丢弃这个版本之后的修改,也就是说我们的项目,完全回到了这个版本的时候的状态

回到之前的版本容易,但是如果这个时候我又想恢复回去,该怎么搞呢???

  • 借助 git reflog 查看历史操作记录(当然也可以直接在git服务器的commit历史上去查)
  • 第二种姿势就是直接git pull拉一下最新的代码... (这种只适用于所有的本地暂存都提交给服务器的情况,当你本地有一个暂存只是commit,但是没有push,那么无法同步到哦,这种case请使用下面的姿势)
# 查询每次操作命令
git reflog

# 找到reset之前的commit id,回滚即可
git reset --hard 3d85a2f

请注意上面的--hard参数,回滚到指定的版本,而且会丢掉之后的改动,那么如果我希望保存修改呢?

git reset --soft 72920bfd579ada7e62ceed2c675bce733e804433

鉴于回退到上一个版本属于非常基础和常见的场景,我们可以使用HEAD^来表示回退到上一个版本,HEAD^2表示回退两个版本,这样就不需要每次去找Commit号了

# 回退到上一个版本
git reset --soft HEAD^
# 回退两个版本
git reset --soft HEAD~2

c. 撤销修改

在我们日常开发过程中,可能会遇到某个文件(or多个文件)上的修改不是我想要的,希望把这些修改都丢弃,这个时候可以怎么办呢?

借助git checkout来实现我们的目的,基本操作姿势如下

git checkout -- README.md

在上图中,详细的演示了修改文件,并丢弃修改的全过程,请注意checkout后面的--,用来指定文件;在后面介绍分支的时候,也会看到这个命令,可以用来切换分支;当后面没有--时,若后面跟上的参数对应分支存在,则切换分支;否则表示丢弃后者工作区中的改动

上面针对的是没有提交到暂存区的撤销,那么针对暂存区的撤销呢?

# 取消暂存
git reset HEAD README.md
# 撤销修改
git checkout -- README.md

既然上面提到了add之后的撤销,那么commit之后的撤销呢?我们上面介绍的版本回退其实就可以实现这个效果

git reset --hard HEAD^

d. commit修改

有些时候,commit对应的注释信息可能不太合适,然后我希望可以修改一下,可以如下操作

git commit --amend

此外,当我们将改动commit到本地分支之后,忽然发现还漏了一个改动,这个时候也可以借助上面的commit --amend来合并提交哦

e. 小结

本节内容主要介绍了版本回退和撤销本地修改的一些操作,主要需要掌握以下几个命令

  • 工作区/暂存区/分支: add将工作区修改提交到暂存区,commit将暂存区修改提交到分支, push将本地分支同步到服务器
  • git log:查看历史的git提交记录
  • git reflog: 本地操作记录
  • git reset --soft/hard commitId: 回退到指定commitId的版本,--soft表示保留修改,--hard表示丢弃修改
  • git checkout -- file: 丢弃指定文件的改动
  • git commit --amend: 提交信息修改和合并

5. 分支

我们上面的所有操作都是在默认的master分支上进行的,但是在实际的业务开发中,基本上没有哪个公司的项目只有一个分支的,试想一下所有的小伙伴都在同一个分支上开发新的功能模块,结果现在出了问题,我们要修复线上bug,但是新开发的功能又不能上线,这个时候就是灾难性的结果了

a. 分支创建

除了在Gitee/GitHub页面创建新分支之外,本地有两种常见的分支创建方式

# 创建分支
git branch dev
# 创建并切换到res分支
git checkout -b res

b. 分支切换

在上面的示意图中已经演示了如何切换分支

# 切换到dev分支
git checkout dev

请注意这里用的也是checkout,与前面丢弃工作区修改命令一致,区别在于后面接上的分支存不存在,存在切换分支;不存在则丢弃修改(丢弃工作区修改,也可以加--来限定)

c. 删除分支

一般建议删除本地分支之前,请确保分支的内容已经合并到主分支,否则可能造成数据丢失哦

# 删除dev分支
git branch -d dev

# 当我们对dev分支有修改,但是没有提交的时候,删除时会提示是否强删
git branch -D dev

d. 分支查询

# 查看本地分支
git branch

# 查看本地+远程分支
git branch -a

e. 分支提交

当我们在新的分支上进行开发,并有需要提交时,直接使用git push多半是不会成功的,这个时候需要指定提交到的远程分支,并建立关系

# 推送远程res分支
git push -u origin res

疑问:本地res分支,能推送到远程的master分支么

请注意上面的提示,并不是推送成功哦

f. 分支合并

创建新的分支,并在新的分支上进行开发,最终必然会有一个将分支内容合并到主分支的过程,分支合并常常会带来另外一个问题,冲突解决,这个会在进阶篇介绍

# 切换主分支
git checkout master
# 将res分支合并到a
git merge res

上面演示的是本地分支的合并,那么如果我希望将远程的res分支内容合并到master分支,可以如何操作呢

# 将远程res分支合并到当前分支
git merge origin/res

g. 小结

本节主要介绍分支相关的基本操作命令,主要包括如下知识点

  • 分支查看:
    • git branch: 查看本地分支
    • git branch -a: 查看本地及远程分支
  • 分支创建
    • git checkout -b new_branch_name: 创建并切换到新的分支
    • git branch new_branch_name: 创建新的分支
  • 分支切换:
    • git checkout new_branch: 切换到新分支(请注意这个和丢弃工作区修改的命令很像哦)
  • 分支删除:
    • git branch -d xxx: 如果分支有未提交修改需要强删,可以用-D
    • git push origin --delete xxx: 删除远程分支
  • 分支提交
    • git push -u origin xxx
  • 分支合并
    • git merge xxx: 将xxx分支合并到当前分支
    • git merge origin/xxx: 将远程xxx分支合并到当前分支

6. 标签

关于标签,可能用得不多,但是我们在看一下看远项目的时候,经常会看到release版,各种里程包,当我们完成一个大的稳定的改造之后,可以考虑添加一个tag,记录一下这个”关键“节点,如果别的小伙伴想使用,优先推荐使用这些release版的,而不是最新的(通常见于开源项目的引入使用)

a. 创建标签

# 创建标签v1.0,绑定最新的commit
git tag v1.0

# 指定comitId绑定tag
git tag v1.0 commitId

# 创建带有说明的标签
tag tag -a v1.0 -m '标签说明' commitId

b. 查看标签

# 查看标签列表
git tag
# 查看标签v1.0对应的信息
git show v1.0

c. 推送标签

将本地修改的标签推送到服务器,常见有两种

# 推送1.0tag
git push origin 1.0
# 推送所有本地未推送的tag
git push origin --tags

d. 删除标签

删除标签和删除分支有点类似,都是用-d

# 删除本地分支
git tag -d 0.9
# 删除远程分支,请注意先确保本地的tag已经被删除了
git push origin :refs/tags/0.9

e. 小结

本节主要的知识点在于tag的创建、查询、推送与删除;当我们需要封release版时,建议可以在gitee/github的项目主页中进行操作

  • 创建标签
    • git tag v1.0: 基于当前的commitId,创建一个v1.0 tag
    • git tag -a v1.0 -m '标签说明' commitId: 基于指定的commitId创建v1.0tag,并且可以通过-m指定标签说明
  • 标签查看
    • git tag / git tag --list: 查询当前有哪些标签
    • git show v.10: 查询v1.0标签对应的信息
  • 标签推送
    • git push origin v1.0: 推送本地v1.0标签到远程
    • git push origin --tags: 同步本地所有未提交的tag
  • 标签删除
    • git tag -d v1.0: 删除v1.0标签
    • git push origin :refs/tag/v1.0: 删除远程v1.0标签(注意执行此操作之前,先删除本地标签)

II. 进阶篇

前面属于基础知识篇,就我个人的看法,除了标签这一块看一看即可,其他的操作,可以说是属于每一个开发者应该掌握的基础知识点;当然仅仅掌握这些基本知识点,在某些时候可能是不够的,接下来将介绍一些可能会提高工作效率的进阶知识点

1. 暂存

a. 实例case

假设我们现在正吭哧吭哧的写新的功能模块,正做得很开心,结果被告知有一个线上bug,需要紧急修复,这个时候就需要把我们做到一半的东西暂存起来,然后切到bug-fix分支上去修复bug,等bug修复完毕之后,再切回来,并恢复之前的操作

b. 提交本地分支恢复方式

根据上面的场景描述,根据前面学习到基本知识点,我们可以如下操作

# 将所有工作区变动提交到暂存区
git add .
# 将暂存区内容提交到本地分支,注意不要这个时候不要将本地分支的内容同步到服务器
git commit -m 'tmp save'
# 切换bug-fix分支
git checkout bug-fix
# ... 修复bug并提交之后,再恢复之前的feature分支
...

git checkout feature
# 恢复到上一次提交
git reset --soft HEAD^

c. stash方式

上面这一套流程可以满足我们上面的场景,但是不够优雅,在git中,针对上面这种场景有一个更好的命令,那就是stash

同样为了实现上述的case,可以如下操作

# 将所有工作区内容提交到暂存区
git add .
# 暂存
git stash 
# 切换bug-fix分支,修复bug
git checkout bug-fix
...
# 切回feature分支,继续业务开发
git checkout feature
# 恢复
git stash pop

d. stash命令小结

上面的case中只演示了两个最常见的stash命令,接下来将详细说一下在实际的工作中,可能接触的命令

  • git stash list: 查看所有的缓存列表

  • git stash: 将暂存区的所有变动保存起来,这个也是我们最常见的使用姿势,但是有一个缺点,就是不知道这次缓存了什么东西

    • git stash save "说明信息": 通过save,在后面加上说明
    • 下图是通过git stash list查看的结果,
      • stash@{1}是我们没有指定描述的case,后面跟上的是stash时最近的一个commit的提交信息
      • stash@{0}是我们指定了描述信息的显示结果
  • git show stash@{num} 显示某次缓存的改动

  • git stash pop stash@{num}: 恢复之前的某个暂存,并且会删除这次暂存

  • git stash apply stash@{num}: 同样是恢复,但是与上面的区别在于不会删除暂存中的内容

  • git stash drop stash@{num}: 丢弃某次暂存

  • git stash clear: 删除所有的暂存

请注意: stash缓存的是暂存区的内容,所以需要先使用git add .将工作区的变动提交到暂存区

下面是一个简单的动态图,演示了git stash的一般使用姿势

2. 解决冲突

关于冲突,可以说是开发者最讨厌遇到的情况了,然而实际的情况是,无论这个项目是只有你一个人开发,还是多人合作开发,冲突多不可避免

case1. 分支合并冲突

每一个git项目都有一个默认的主分支(master分支,最近因为歧视问题,被提议改成main...),通常在其他分支上的修改最终都会合并到master分支上,这里就可能出现合并冲突问题

下面根据一个动态示意图,演示一下冲突合并的case

步骤有点长,下面给出具体的case复现步骤

# 创建并切换到fix分支git checkout -b fix

# 在fix分支上做一些修改,并提交到分支echo 'fix some' 1> README.md
✗ git add .git commit -m 'fix branch'

# 切换master分支,在同样的文件上做修改,并提交到本地分支git checkout master
✗ echo 'main fix' 1> README.md
✗ git add .git commit -m 'main fix' 

# 分支合并,将本地fix分支的内容,合并到master分支,请注意这个时候会提示冲突git merge fix
main fix
自动合并 README.md
冲突(内容):合并冲突于 README.md
自动合并失败,修正冲突然后提交修正的结果。

# 这个时候我们可以丢弃合并git merge --abort

# 也可以选择解决冲突,直接通过vim进去,会看到冲突的地方被 `<<<<<<<<<<<<` 与 `>>>>>>>>` 包裹起来了vim README.md
# 冲突解决完毕之后,提交git add .git commit

case2. 多人协作冲突

多人协作的冲突问题可以说是最常见的case了,我和其他的小伙伴同时修改了某个文件,而其他的小伙伴又是先与我提交的,这个时候,再同步最新代码的时候就会出现冲突问题

请注意上图中的上下两个窗口分属本地两个不同git-study工程,这个冲突主要是我们在提交之前,同步远程信息时,提示冲突了,一般的解决思路也比较明确,根据冲突文件,找到冲突的地方,fix掉,然后git add . + git commit即可

请注意,上面合并完毕之后,除了我们之前的commit之外,还会新增了一个merge的commit

小结

这一小节主要介绍了常见的两种导致冲突的case,一般来讲解决冲突依然是需要靠我们人工去选取最终保留的代码

一般推荐的使用姿势

  • 提交代码之前,先拉一下最新改动: git pull
  • 如有冲突,修改完毕之后,记得执行git commit来提交冲突的fix
  • 如不想保存冲突合并,可以执行git merge --abort丢弃合并

3. rebase

a. 使用背景

在上面介绍多人协作导致的冲突的时候,解决完之后,发现最终会新怎给一个merge的commit,也就是说我们的这一次提交会有两个commit(一个是我们之前的准备提交的内容,一个是合并冲突解决的commit)

此外,我们再看一下上面冲突解决之后的分支情况

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

除了上面命令行的查看方式之外,也可以直接在gitee/github网页上查看分支网络图,可能更加直观

那么我们的问题来了

  • 我们是否可以只保留一个commit
  • 我们是否可以让git的提交历史是一条直线,而不出现交叉呢

b. reabse使用

同样是上面的case,某个小伙伴修改readme.md并提交了rebase testcommit;然后我们同样修改readme.md,但是注意这次同步最新代码使用的是git pull --rebase

上面的动态有点长,下面简单的说一下关键点

# 本地修改,并提交到本地分支
git add .
git commit -m 'main branch save'

# 注意这里同步使用命令
git pull --rebase

# 因为发生冲突,这个时候可以看到我们当前的工作区不在master分支上了
# 我们需要在新的分支上解决冲突,解决完毕之后,同样的提交
git add .
git commit

# 提交完毕之后,我们希望回到master分支,注意这里不是使用 git checkout master来切换分支, 而是使用下面的命令
git rebase --skip
# 如果我们不希望保留这次的合并,可以执行以下命令丢弃
git rebase --abort

# 切换回master分支之后,我们查看当前log,和分支网络图
git log --graph --pretty=oneline --abbrev-commit

c. 小结

一般来讲我们推荐在提交之前先同步最新代码,这个时候使用git pull --rebase可能是一个更好的选择

当出现合并冲突时,会进入一个临时的分支,这个时候我们需要做的是下面四步

  • fix 冲突
  • git add / git commit: 提交冲突的解决
  • git rebase --skip: 冲突已解决,回到之前的分支
  • git push: 同步本次修改

为什么推荐使用rebase

  • 分支历史提交为一条直线,不会分叉,更直观
  • 一个commit,对于诸如使用gerrit来做代码权限管理时,更加友好

可不可以不用rebase

  • rebase看起来有点麻烦,这个知识点我个人认为并不属于基本功能,不掌握也不会影响日常的工作流程

4. gitignore

如果我的项目里面并不是所有的内容都需要提交,然而我又特别喜欢通过git add .来讲所有工作区内容提交到暂存区,这个时候咋办?

  • 借助.gitignore文件来排除需要提交的文件

a. 规则说明

在项目根目录下,新增文件.gitignore

  • 以斜杠/开头表示目录;
  • 以星号*通配多个字符;
  • 以问号?通配单个字符
  • 以方括号[]包含单个字符的匹配列表;
  • 以叹号!表示不忽略(跟踪)匹配到的文件或目录;

b. 实例说明

# 过滤logs文件夹,及文件下所有的文件
/logs
# 所有以.开头的文件都过滤掉
.*
# .gitignore 文件不忽略
!.gitignore

说明:在我们新建.gitignore之前,一些可以被忽略掉的文件已经进入暂存区,可以怎么处理呢?

  • git rm -r --cached 文件夹: 针对文件夹,递归删除
  • git rm --cached 文件: 针对文件,指定删除

5. 分子合并的三种姿势

在基础篇中我们介绍了直接使用git merge来合并分支的case,但是一般不建议直接使用这种方式,更过的是推荐加上参数--no-ff

这里我们将简单的介绍下合并的三种可选方式

  • fast-forward: 默认方式,如果顺着一个分支走下去可以到达另一个分支的话,那么 Git 在合并两者时,只会简单地把指针右移,当分支删除时会丢失merge信息
  • squash: 将分支上的所有变动合并带过来,不提交,需要手动添加一次commit来指定提交信息
  • no-ff: 在提交的时候,会创建一个merge的commit信息,然后合并分支

上图给出一个实例演示下三种合并方式的区别

  • fast-forward 直接合并,无merge关键节点
  • squash: 分支所有变动合并过来,需要额外的手动添加commit提交到当前分支(对应分支的所有commit没有)
  • no-ff: 合并并创建一个merge的commit信息(推荐使用这种方式,有对应分支的历史提交,有合并节点)

借用网上的一张图,来表示他们三个的区别

6. 项目配置

在上面最开始介绍环境配置的时候,我们一般会设置一个全局的用户名/邮箱,然而实际情况,公司内的项目提交需要用公司内网邮箱;而我自己的git项目,希望用私人邮箱,这个时候全局的配置就不适合了

针对这种case,可以如下处理

# 进入配置文件vim .git/config


# 新增下面的配置,保存并退出
[user]
        name = 一灰灰
        email = yihuihuiyi@gmail.com

当我们再次进行提交时,查看一下git log

(上面这个也演示了为啥同一个git项目,就我一个参与者,为啥会有多个用户列表了)

https://gitee.com/liuyueyi/git-study/contributors?ref=master
https://gitee.com/liuyueyi/git-study/contributors?ref=masteropen in new window

7. 删除文件及历史记录

据说因为github导致的密钥泄露问题比较普遍,我们知道git的强大之处在于它可以记录你的所有提交,可以追溯某个文件从创建到最终的销毁的所有历史,因此当你不小心将某些敏感信息提交到git仓库之后,即便你马上发现并删除,但是别人依然可以“顺藤摸瓜”找到

那么当我错误的提交了一个敏感文件到git仓库,有没有挽救办法呢,还是说只能删库重来?

上图演示了我们在gitee上删除这个文件之后,依然可以通过历史的commit找到对应的提交内容

下满是一个解决办法

git filter-branch -f --tree-filter 'rm -rf senstive.txt' HEAD
# 强制提交, 非特殊情况,不建议使用这个命令
git push origin --force

当我们再次进行查看时,在历史的提交中也找不到senstive.txt文件了

8. 统计

最后给一个小工具,统计一下自己过去一年某个项目的工作量

git log --author="$(git config --get user.name)"  --before='2020-12-31 23:59:59' --after='2020-01-01 00:00:00' --pretty=tformat: --numstat | awk '{ add += $1 ; subs += $2 ; loc += $1 - $2 } END { printf "added lines: %s removed lines : %s total lines: %s\n",add,subs,loc }'

下图给出了我quick-mediaopen in new window从诞生到现在的所有改动情况(代码删得多,说明时不时会重构一把😝)

III. 归纳总结

本篇作为程序猿必备技能第一篇,git可以说是每个小伙伴都应该掌握的知识点,本文划分了基础与进阶两段,内容都不算难,花10-15分钟读完之后,基本上就可以了解git怎么玩了

因为内容篇幅较长,所以我们这里也敲一敲黑板,画一下重点

1. 同步修改提交三把斧

日常业务工作中,最最常见,最最基础的步骤

# 提交本地修改
git add .
git commit -m 'save'

# 同步最新代码
git pull --reabse

# 冲突时,先解决冲突
fix conflict
git add .
git commit 
# 解决完冲突,回到之前的分支
git rebase --skip

# 没有冲突/or冲突已解决时,直接提交
git push 

2. 查看变动

当我们想知道哪些文件被修改,修改了啥时,常用的几招

# 可以查看工作区 + 暂存区的所有变动
git status

# 查看工作区的变动
git diff

# 查看暂存区的变动
git diff head^

3. 历史查看

通过git log可以查看历史提交,通过log,可以做很多事情,下满只给常用的几种

# 查看git历史
git log

# 一行展示,方便阅读
git log --pretty=oneline

# 图方式查看历史变动情况
git log --graph --pretty=oneline

此外还有一个git reflog也有可能会用到,查看本地仓库的变动

4. 分支

分支的几大操作,无非创建,切换,查看,删除以及合并

  • 创建: git branch newBranch
  • 创建并切换: git checkout -b newBranch
  • 切换分支: git checkout newBranch
  • 分支列表: git branch / git branch -a
  • 删除分支: git branch -d/D branchName
  • 合并分支到当前分支: git merge newBranch
  • 合并远程分支到当道分支: git merge --no-ff origin/newBranch

关于分支合并,推荐使用--no-ff来替代默认的fast-forward合并方式

5. 版本回退与撤销修改

使用reset来实现版本回退;使用checkout来撤销修改

  • 回退到指定的commit: git reset --soft/hard commitId
    • soft; 表示保留这个commitId之后的所有修改
    • hard: 完全恢复commitId这个时候的状态
  • 取消暂存: git reset HEAD . 暂存区所有变动回到工作区
  • 撤销工作区修改; git checkout .

6. 标签

标签更多的是立flag,打里程包,方便给其他的小伙伴稳定的引入

  • 创建标签
    • git tag v1.0: 基于当前的commitId,创建一个v1.0 tag
    • git tag -a v1.0 -m '标签说明' commitId: 基于指定的commitId创建v1.0tag,并且可以通过-m指定标签说明
  • 标签查看
    • git tag / git tag --list: 查询当前有哪些标签
    • git show v.10: 查询v1.0标签对应的信息
  • 标签推送
    • git push origin v1.0: 推送本地v1.0标签到远程
    • git push origin --tags: 同步本地所有未提交的tag
  • 标签删除
    • git tag -d v1.0: 删除v1.0标签
    • git push origin :refs/tag/v1.0: 删除远程v1.0标签(注意执行此操作之前,先删除本地标签)

7. stash暂存

通过stash将当前的工作内容暂存起来,然后去做其他的事情;做完之后再回来接着之前的工作继续

实际的工作中可能用得不多,但是用的好的话,可以省很多事情

  • git stash list: 查看所有的缓存列表
  • git stash/git stash save "说明信息": 暂存
  • git show stash@{num} 显示某次缓存的改动
  • git stash pop stash@{num}: 恢复之前的某个暂存,并且会删除这次暂存
  • git stash apply stash@{num}: 同样是恢复,但是与上面的区别在于不会删除暂存中的内容
  • git stash drop stash@{num}: 丢弃某次暂存
  • git stash clear: 删除所有的暂存

8. Git操作图

最后附上一个神图,介绍了各种git命令, 原文点击下载open in new window

基础操作
基础操作
进阶操作
进阶操作

9 . 配套讲解视频

为了更友好的演示git的基本使用,特意录制了一个视频,由于是第一次录制,效果不是特别好,凑合的话还是能看,请各位大佬轻喷

对应的视频地址如: 程序猿基本功系列:项目管理工具GIT全解open in new window

Loading...