Git常用命令总结(通俗易懂)


一、 Git 基本知识

  Git是当前最流行的分布式版本控制系统(Distributed Version Control System)由Linux之父linus所创建,底层由C语言实现。Git比传统的CVS、SVN集中式版本控制系统,更先进,使用范围也更广,世界上最大的免费代码托管平台Github就是利用Git进行版本控制的。
  Git是Linus Torvalds为帮助Linux操作系统开发而创造的,其实Linux系统早期开发时采用的版本控制器是BitKeeper,但由于Linux开发社区中,开发Samba的Andrew尝试破解BitKeeper的协议,于是BitKeeper的东家BitMover公司决定收回Linux社区对于BitKeeper的免费使用权,在这种情形下Linus自己就用C语言写了一个分布式版本控制器(Git的中文意为混账、饭桶,不知道linus咋想的,23333~)
  本文是小编对Git日常使用命令的总结回顾,好记性不如烂笔头!


  Git包含4个区域,工作区(Working Directory),暂存区(Stage/Index)、本地仓库(Repository)和远端仓库(Remote Directory),通常的操作是:在本地git clone克隆远端仓库后,git add filename将工作区中新创建和修改的文件添加到暂存区,之后git commit -m "commit log message"将暂存区中的内容添加到本地仓库,最后git push将本地仓库同步到远端仓库,若想撤销工作区文件,可采用git restore filename (亦说git checkout -- filename,具体命令以终端提示为准),撤销暂存区中的文件,可采用git restore ----staged filename(亦说git reset HEAD filename,以个人电脑终端提示为准)。文件在这四个区域之间具体的转换关系如下图所示:
在这里插入图片描述

二、分支管理*

  分支管理是Git比较重要的部分,包含分支的:创建、切换、查看、删除、合并等操作。

2.1 分支创建与查看

  创建分支时明确两点即可:1. 我应该从哪里拉新的分支;2. 根据己方需求给分支创建一个合理的名字。

  假设创建的分支名为feature/login,创建分支可以先在远端网页创建好分支然后同步到本地,若从主干拉,Branch Source就选master,从其他的分支拉就填写对应的分支名,远端创建好分支后,就用git pullgit fetch命令同步到本地,之后采用git checkout feature/logingit switch feature/login切换到对应分支即可。有些shell在git pull或git fetch后本地可以感知到新创建的分支,但是有些shell却感知不到,此时需要用户在本地手动创建分支,然后将本地分支和远端分支进行关联,具体操作为:git branch feature/login; git checkout feature/login; git branch --set-upstream-to=origin/feature/login。除了在远端创建分支后同步至本地,还可以直接在本地创建分支然后推送至远端仓库,做法为:在本地创建新分支后,照往常进行操作,只不过最后git push时,由于远端仓库并没有该分支所以会报错,需要将git pull替换为git push --set-upstream origin feature/login

  创建分支时,不同的需求有不同的分支命名规范,主干分支毫无疑问是master(Github主干名为main,改master为main是为了政治正确,用master易让人联想到master and slave,有种族歧视之嫌),如果是功能需求开发,分支名以feature开头;若为bug修复,则用bugfix或hotfix开头;若为发布分支,则用release开头,若为个人分支则以personal开头。

  查看分支有三条命令:查看本地分支:git branch;查看远端分支:git branch -r;查看所有分支:git branch -a


2.2 分支切换

  分支间的切换,git checkout branch_namegit switch branch_name命令均可实现分支跳转,分支跳转前,需要保证当前分支的工作区和暂存区是干净的,否则会出现切换失败即使分支切换成功,也会将当前分支工作区和暂存区的内容带到别的分支中,造成混乱(因为工作区和暂存区是所有分支共享的)

  考虑实际开发中的一个场景:本分支还在代码开发中,但出于某种需要,急需切换到其他分支进行操作,该如何处理?前面我们说过,分支切换的前提是当前分支的工作区和暂存区是干净的,所以可以git commit提交一次,之后再切换到目的分支;这样的做法不算优秀,因为会产生一个无意义的提交。面对这种情景,常用的做法是用git stash暂存现场,git stash后当前分支的工作区和暂存区会变的干净,随后切换到目的分支进行操作,操作完毕后切换回原分支,输入git stash pop恢复现场即可。(注:命令git stash对于已经被跟踪的文件才会有效!文件只要曾被git add 添加到暂存区,该文件就是被跟踪)

  关于git stash有一系列命令,首先git stash后会生成一个保存列表,可通过git stash list查看,git stash可以多次运行,保存列表中的保存记录也会随之增加。git stash是以栈的顺序保存,故git stash pop弹出的是最近一次的暂存记录。此外还可以通过git stash pop stash@{序号}的方式 (序号从0开始递增),指定需要弹出的暂存现场。git stash pop 等价于 git stash apply (恢复保存记录中的第一个保存现场) + git stash drop (从保护记录中删掉第一个保护记录),此外git stash还有git stash clear 清空保存列表中所有的保存记录,等等,此处不细说,读者可自行搜索git stash相关知识点。


2.3 分支合并

  当某个分支开发完毕,经测试无误后,需将该分支合入master主干,在分支合并时通常会出现合并冲突,需要手动解除
  介绍分支合并之前先看一下git pull 和 git pull -r,它们都是拉取远端仓库同步至本地,git pull包含两个动作:git fetch + git merge,而git pull -r底层为:git fetch + git rebase,所以git pull和git pull -r的区别也就在于git merge和git rebase。

  首先来看git merge,假设需要将 master 分支合并到 feature 分支,命令如下:git checkout feature; git merge master,这样就可以成功将master合并到feature分支上。Merge 好在它是一个安全的操作。现有的分支不会被更改,避免了 rebase 潜在的缺点。但另一方面,这同样意味着每次合并上游更改时 feature 分支都会引入一个外来的合并提交。如果 master 非常活跃的话,这或多或少会污染你的分支历史,git log查看提交日志也会有些杂乱。

  之后来看一下git rebase,假设需要将feature分支并入master分支,命令如下:git checkout feature;git rebase master,它会把整个 feature 分支剪切移动到 master 分支的后面,有效地把所有 master 分支上新的提交并入过来,rebase最大的好处是你的项目历史会非常整洁。首先,它不像 git merge 那样引入不必要的合并提交。其次,rebase后的项目历史呈现出完美的线性。不过,这种简单的提交历史会带来两个后果:安全性和可跟踪性。如果你违反了 rebase 黄金法则,重写项目历史可能会给你的协作工作流带来灾难性的影响。此外,rebase 不会有合并提交中附带的信息——你看不到 feature 分支中并入了上游的哪些更改。


2.4 分支删除

  分支删除主要包含三条命令:(1) 删除本地分支:git branch -d branch_name;(2) 若待删除的分支从未有过合并操作,则需要改小d为大D:git branch -D branch_name;(3) 删除远端分支:git push origin --delete branch_name,注意这里的branch_name和本地保持一致即可,不再需要加上origin/前缀,–delete前面已经有origin了。


三、其他操作理解

3.1 版本回退(慎用)

  介绍版本回退前,先介绍分支指针和HEAD指针。分支名的本质其实就是分支指针,它会指向某个具体的提交记录。在Git中随着不断commit提交以及创建分支,提交记录也从最开始的一个点演变成一棵提交树,那么Git是如何知道你在提交树的哪个位置工作呢?答案就是HEAD指针,可以通过cat .git/HEAD命令查看HEAD,如果 HEAD 指向的是一个引用,还可以用 git symbolic-ref HEAD 命令查看它的指向,HEAD指针既可以指向提交树中某个具体的提交记录,也可以指向分支指针一个常见的指向关系是:HEAD指针指向分支指针,分支指针指向当前分支最近的一个提交记录,当该分支产生一个新的提交记录时,分支指针会随之后移。此外,既然他们都是指针,自然就可以移动指针的指向,让他们在提交树中自由移动,当HEAD指针不指向分支指针,而是指向某个具体的提交记录时,此时我们称HEAD指针处于detached游离态

  HEAD和分支指针的移动方式有两种:绝对引用和相对引用,绝对引用是指将指针移动到指定commt id的提交记录上(每一个commit记录都会有一个commit id,它是一个长度为40的16进制哈希值,实际使用时不需要全部写出,只要写出前若干位,保证不出现二义性即可),绝对引用通过指定提交记录哈希值的方式在 Git 中移动不太方便, 这需要你清楚提交树的结构,以及提交记录的commit id。因此使用更多的是相对引用,相对引用是相对当前工作位置而言的,通常采用上尖号和波浪号实现。

  移动HEAD指针,git checkout commit_id 或者采用相对引用,如git checkout bugFix^ : 将HEAD指向BugFix分支指针的父节点, git checkout HEAD~2: HEAD指针顺着提交记录向上移动两次,指向之前所指对象的爷爷节点。
  移动分支指针就是强制修改分支位置,常用命令为:git branch -f 目标节点,同样可采用相对引用和绝对引用两种移动方式。

  OK,介绍完HEAD指针和分支指针,我们回到原问题:如何实现版本回退,版本回退主要是git resetgit revert两个命令。git reset 通过把分支记录回退几个提交记录来实现撤销改动。你可以将这想象成“改写历史”。git reset 向上移动分支,原来指向的提交记录就跟从来没有提交过一样。例如: git reset --hard HEAD~2; git push -f(这样的操作一定要谨慎使用,一旦出错,容易被打,也正是因为该命令的风险性,许多公司明令禁止使用 git reset 命令回退代码)。相较于git reset,更推荐的命令是git revert,该命令不会删除提交记录,而是恢复到某提交记录之前的状态,并生成一个新的提交记录,以下图为例,C和D都是错误的提交,都要回退,此时我们先要回退D,git revert 5lk4er后D的提交记录就被撤回,生成D’,这里的D’和C是等价的,之后再git revert 76sdeb,就会回退C,生成C’,C’ 的状态和B是一样的。这样就实现了C和D的回退。
在这里插入图片描述


  一篇文章想较好且全面的介绍Git是不可能的,本文只是小编自己对Git日常使用做了一个简单的总结回顾,Git还有很多操作命令,且关于blob、tree、commit、tag等Git底层构成和hash原理,还有待后续深入学习。路漫漫其修远兮,吾将天天写代码,与君共勉!


三、参考资料

  1. https://www.liaoxuefeng.com/wiki/896043488029600
  2. https://www.bilibili.com/video/BV1zY411E7yM?p=1&vd_source=b7a35e7cf7e78d10f95244a2c6723095
  3. Git在线闯关练习网站(推荐哦~):https://oschina.gitee.io/learn-git-branching/
  4. git reset 和 git revert:https://blog.csdn.net/fly910905/article/details/88635673
  5. git rebase 和 git merge: https://github.com/geeeeeeeeek/git-recipes
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值