Git 常用命令知识笔记

Git 仓库数据结构

  • Git 仓库由一个个的 commit 组成
  • 某些 commit 上会有一些 branch 指向它们,这些 branch 的本质是引用
  • 有一个特殊的引用叫做 HEAD,它始终指向当前的位置,这个位置可以是 commit,也可以是 branch

staging area 暂存区和 add

  • staging 原意:舞台表演前的筹划准备(例如汇集道具和演员)。Git 中的意思:把改动内容汇集起来以待提交。
  • staging area:待提交的修改内容暂时存放的地方。主要用于和已经改动但不打算提交的内容区分开来。
  • add 指令:把指定的内容放进暂存区。
  • Workspace:工作区
  • Stage:暂存区
  • Repository:仓库区(本地仓库)
  • Remote:远程仓库
bash 复制代码
git add [file1] [file2] ...                # 添加指定文件到暂存区
git add [dir]                              # 添加指定目录到暂存区,包括子目录
git add .                                  # 添加当前目录的所有文件到暂存区
git add -p                                 # 添加每个变化前,都会要求确认
										   # 对于同一个文件的多处变化,可以实现分次提交
git rm [file1] [file2] ...                 # 删除工作区文件,并且将这次删除放入暂存区
git rm --cached [file]                     # 停止追踪指定文件,但该文件会保留在工作区
git mv [file-original] [file-renamed]      # 改名文件,并且将这个改名放入暂存区 

git commit

  • commit 表示对于一次改动的提交,它可以代表当前时刻下 Git 仓库的完整快照,但本质上,commit 只是记录了距离上一次 commit 之间的改动。
bash 复制代码
git commit -m [message]                          # 提交暂存区到仓库区
git commit [file1] [file2] ... -m [message]      # 提交暂存区的指定文件到仓库区
git commit -a                                    # 提交工作区所有更改到仓库区
git commit -v                                    # 提交时显示所有diff信息
git commit -am 'message'                         # 将add和commit合为一步

# 使用一次新的commit,替代上一次提交
git commit --amend -m [message] # 如果代码没有任何新变化,则用来改写上一次commit的提交信息(用于反复修改)
git commit --amend [file1] [file2] ... # 重做上一次commit,并包括指定文件的新变化

branch 和 master

  • branch 的含义是分支,指的是仓库结构出现分叉时的不同的「叉」
  • 本质上,git 的 branch 是引用(reference),即指向某个 commit 的指针

直观感觉的 branch:

而实质上的 branch:

所以,branch 和你什么时候创建的它无关,也和仓库的起点无关,只和它当前指向哪个 commit 有关。

  • master 是⼀个特殊的 branch,因为它是 Git 的默认 branch(默认 branch 可以修改)。默认 branch 的特点:
    • 执行 clone 方法把仓库取到本地的时候,默认 checkout 出来的是默认 branch,即 master;
    • 执行 push 命令把本地内容推送到远端仓库的时候,远端仓库的 HEAD 永远跟随默认 branch,而不是和本地 HEAD 同步。换句话说,只有 push master 分支到远端的时候,远端的 HEAD 才会移动。
bash 复制代码
git branch                    # 列出所有本地分支
git branch -r                 # 列出所有远程分支
git branch -a                 # 列出所有本地分支和远程分支
git branch -v                 # 查看各个分支最后一次提交
git branch --merged            # 查看哪些分支合并入当前分支
git branch --no-merged         # 查看哪些分支未合并入当前分支
  
git branch [branch-name]      # 新建一个分支,但依然停留在当前分支
git checkout -b [branch]      # 新建一个分支,并切换到该分支
git branch [branch] [commit]  # 新建一个分支,指向指定commit
git checkout -                # 切换到上一个分支

git branch -d [branch-name]            # 删除分支
git branch -D mybranch                 # 强制删除分支
git push origin --delete [branch-name] # 删除远程分支
git branch -dr [remote/branch]         # 删除远程分支
  • HEAD 也是引用,但它不是 branch,它代表了当前所处的位置。HEAD 不仅可以指向某个 commit,也可以指向某个 branch(例如 master、feature1)
  • 当每次 commit 的时候,HEAD 不仅随着新的 commit 一起移动,而且如果它指向了某个 branch,那么它也会带着 branch 一起移动

git clone

  • clone 是从远端仓库初次把数据取下来:
bash 复制代码
git clone https://github.com/xxxx.git

clone 命令具体会做两件事:

  1. 把整个仓库中的所有 branch 取下来,并把从初始 commit 到达这些 branch 的路径上的所有 commit 都取下来:
  2. 从初始 commit 开始,向 master 指向的 commit,一个个地把每个 commit 应用,最终得到一个「当前」状态的仓库内容,写进 Git 所在的目录(这个目录叫做 working tree)

git log

  • 从 HEAD 指向的 commit 开始,倒序 显示每一个 commit 的摘要信息(最新的排在最前面)
bash 复制代码
git status        # 显示有变更的文件
git log           # 显示当前分支的版本历史
git log --stat    # 显示commit历史,以及每次commit发生变更的文件
git log -S [keyword]  # 搜索提交历史,根据关键词
git log [tag] HEAD --pretty=format:%s  # 显示某个commit之后的所有变动,每个commit占据一行
git log [tag] HEAD --grep feature      # 显示某个commit之后的所有变动,其"提交说明"必须符合搜索条件
git log --follow [file]                # 显示某个文件的版本历史,包括文件改名
git whatchanged [file]
git log -p [file]                      # 显示指定文件相关的每一次diff
git log -5 --pretty --oneline          # 显示过去5次提交
git shortlog -sn                       # 显示所有提交过的用户,按提交次数排序

git merge

  • merge 就是合并,它会把当前 commit 和指定 commit(所谓 commit,可以直接用它的 hash 值来指定,例如 4a0a1b ,也可以用一个直接或间接指向它的引用来指定,例如 master 或者 HEAD )进行合并,并把这个合并行为创建成一个新的commit。
bash 复制代码
git merge feature1       # 合并feature1分支至当前分支
git merge origin/master  # 合并远程master分支至当前分支

git merge 会产生一个新的提交。

merge 行为所产生的 commit,是一种特殊的 commit:

  1. 它不需要有改动,只要指定两个(或更多个)父 commit 就好
  2. 正如上面这句说的,它有两个或更多个父 commit,这是一般的 commit 不具有的性质

git checkout master 相当于merge from master,git merge mybranch 相当于 merge from mybranch。

merge 冲突

当 Git 不知道怎么合并某两处冲突的修改时,会中断自动合并,并对冲突文件进行标记。解决方法:

  1. 把文件手动修改好
  2. 把修改的内容使用 add 来添加进暂存区
  3. 用 git merge --continue 来继续自动合并流程

关于 origin/ 打头的 branch

  • 本地仓库中,有一些以 origin/ 打头的 branch,它们是远端仓库(别名为origin)的本地镜像。它们的作用是方便在本地查看远端仓库的 branch 状态。

远端仓库默认名称是 origin,但也可以给它们起别的名称

origin/ 分支并不在本地直接操作,它们一般只在两种情况下会进行自动更新:

  1. 在执行 push 的时候,push 成功后,push 成功的 branch 会把它对应的 origin/ branch更新到当前 commit(因为远端的 branch 已经随着 push 的成功而更新,所以本地镜像也一起更新)
  2. 在执行 pull 或者 fetch 的时候,由于从远端拿到了所有最新的 branch 状态,所以也会一同更新所有的 origin/ branch

关于 origin/HEAD:这是一个永远跟随 origin/master 的引用,它最大的作用是用来标记默认 branch

git push

  • 把当前的本地分支推送到远端仓库的指定分支。
bash 复制代码
git push origin feature1

具体做两件事:

  1. 把 HEAD 所指向的 branch (只是一个引用哦)推送到远端仓库
  2. 从这个 branch 向前回溯,远端仓库缺少的每一个 commit 也推送到远端仓库。
  3. 将 push 的 branch 的本地镜像 origin/xxx 更新




注意:origin/HEAD 并没有在图上画出来,但如果 push 是 master(即默认branch),那么本地的 origin/HEAD 也会更新到 master 的最新位置;当push 的是其他 branch 的时候,origin/HEAD 并不会更新。

也就是说, origin/HEAD 只和默认分支相关,和 HEAD 是无关的。

bash 复制代码
git push [remote] [branch]   # 上传本地指定分支到远程仓库
git push [remote] --force    # 强行推送当前分支到远程仓库,即使有冲突
git push [remote] --all      # 推送所有分支到远程仓库
git push origin master       # 将当前分支push到远程master分支

git pull

  • 把远端 branch 取到本地。
bash 复制代码
git pull origin feature1

具体做的事有三件:

  1. 把远端所有 branch 的最新位置更新到本地的 origin/xxx 镜像
  2. 要到达这些 branch,本地所缺少的所有 commit,也取到本地
  3. 把 origin/当前branch 的内容合并到当前 branch




事实上,git pull origin feature1 会分成两部执行,它等价于下面两行:

bash 复制代码
git fetch
git merge origin/feature1

git fetch 的含义:

bash 复制代码
git fetch [remote]   # 下载所有远程分支,但不更新本地分支(另需merge) 

git checkout

  • 移动 HEAD,让它指向某个 commit 或某个 branch。
  • checkout --detach :让 HEAD 脱离当前 branch,直接指向下面的commit。
bash 复制代码
git checkout -b dev origin/master 

从远程的 master 分支检出到本地的dev上,并切换到新建的本地dev分支上。

其实也是相当于两个命令的缩写:

bash 复制代码
git branch dev  # 创建分支
git checkout dev # 切换分支

本地的项目中,一直都保留着一个master分支,并关联远程的master分支。本地的master分支,你可以当作是个干净的主线,每次新来一个需求的时候你都可以以该分支为基准,新建一个分支进行开发,最后进行合并,并由这个基准分支(本地master)提交到远程;具体的专业信息你可以参照文档:Git-分支-分支的新建与合并

通过 checkout 可以恢复指定文件(如不小心commit掉的)到工作区(未提交状态):

bash 复制代码
git checkout [file]             # 恢复暂存区的指定文件到工作区
git checkout [commit] [file]    # 恢复某个commit的指定文件到暂存区和工作区
git checkout .                  # 恢复暂存区的所有文件到工作区
bash 复制代码
git checkout -b master_copy                               # 从当前分支创建新分支master_copy并检出
git checkout -b master master_copy                        # 上面的完整版
git checkout features/performance                         # 检出已存在的features/performance分支
git checkout --track hotfixes/BJVEP933                    # 检出远程分支hotfixes/BJVEP933并创建本地跟踪分支
git checkout v2.0                                         # 检出版本v2.0
git checkout -b devel origin/develop                      # 从远程分支develop创建新本地分支devel并检出
git checkout -- README                                    # 检出head版本的README文件(可用于修改错误回退)

git rebase

  • 把当前 commit(以及它之前的 commits)应用到指定的需要 rebase 的 commit上。

Git 中的每一个 commit 都是不会改变的,所以 rebase 之后的每个 commit 都是新产生的,而不是对原先的 commit 进行「修改」

rebase 冲突

rebase 的冲突解决方法和 merge 冲突一样,只是把 git merge --continue 改成 git rebase --continue 就行了。

git reset

  • 把当前 branch 指向指定的 commit。
bash 复制代码
git reset [指定commit] # 重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变

移动到指定 commit,并保留 working tree 的内容。

bash 复制代码
git reset --hard [指定commit]

移动到指定 commit,并重置 working tree。

bash 复制代码
git checkout .                         # 撤销未暂存修改
git reset                              # 撤销未提交的暂存至 git add . 状态
git reset --hard                       # 撤销所有修改,保持与上一次一致
git reset --hard origin/master         # 撤销本地提交
git reset --hard HEAD^ & git push --f   # 撤销已推送
git reset --keep [commit]              # 重置当前HEAD为指定commit,但保持暂存区和工作区不变

reset 和 checkout 的区别

它们都是移动 HEAD,但 chekcout 移动的时候是自己移动,不带着 branch 一起;而 reset 会带着 branch 一起移动。

git tag

bash 复制代码
git tag                     # 列出所有tag
git tag [tagname]           # 新建一个tag在当前commit
git tag [tagname] [commit]  # 新建一个tag在指定的commit
git tag -d [tagname]        # 删除本地tag

另⼀种引用类型。作用:设置持久标记,例如版本号。和 branch 区别:

  • 不能改变
  • 不能被 HEAD 指向
  • origin/master, origin/feature, origin/HEAD 和 tag 有相似之处:也不能从本地改变位置,也不能被 HEAD 指向
bash 复制代码
git tag                          # 显示已存在的tag
git tag -a v2.0 -m 'xxx'         # 增加v2.0的tag
git show v2.0                    # 显示v2.0的日志及详细内容
git log v2.0                     # 显示v2.0的日志
git checkout v2.0                # 检出版本v2.0

git checkout v2.0 会把远程 tag v2.0拉到本地,在本地创建一个无Head指向的分支,而远程tag分支不受任何影响,将本地分支push后将发布一个新的分支。

基于 tag 的 git check out 出来的分支可以执行 git branch xxx 创建新的本地分支,然后git check out xxx , commit后push到远端可以创建一个新分支(也可以不提交)。

bash 复制代码
git push [remote] [tag]         # 提交指定tag
git push [remote] --tags        # 提交所有tag
git checkout -b [branch] [tag]  # 新建一个分支,指向某个tag
git push origin :refs/tags/[tagName] # 删除远程tag

git revert

  • 撤销指定的提交,用于已经 push 到 master 的内容需要删除。它的原理是创建一个新的commit,内容是指定 commit 的「相反内容」。
bash 复制代码
# 新建一个commit,用来撤销指定commit 后者的所有变化都将被前者抵消,并且应用到当前分支
git revert [commit]

git cherry-pick

  • 选择指定的某个或某些commit,合并进当前分支。 将 commit 到 HEAD 处。
bash 复制代码
git cherry-pick [commit1] [commit2]
git cherry-pick ff44785404a8e           # 合并提交ff44785404a8e的修改

⽐如我想抛弃某个 branch,这个特性不要了,但它的某两个 commit 我希望保留。

git reflog

bash 复制代码
git reflog <branch>

查看指定的引用(HEAD 或 branch)的移动历史,从而找到之前的某个特定 commit

branch 的作用

  • 让项目可以同时做多件事
  • 未做完的事不会被项目真正收录

Feature Branching

  • 做法:每开发一个新的功能做一个修复,都使用单独的分支,在做完之后 merge 到 master 去
  • 本地 merge:由于别人可能在你之前 push 过,所以你的 push 可能失败。所以通常会需要先 pull 一下,然后再 push。
  • 使用 github:先创建 pull request,在同事审阅完成之后,通过按钮实现在线 merge
  • pull request 是什么:是开发者对远端仓库的提出的「拉取某个 branch」的请求

Git Flow

两条持久主线:master 和 develop

master

  • 最稳定的分支(长期分支),只用于存放所有的发布
  • 每次有了新的 commit 之后,立即打一个 tag 来记录
  • 正式发布的集成目标

develop

  • 日常开发分支(长期分支),用于存放不稳定版本的发布
  • develop 并不是直接用于开发 feature 的,开发 feature 需要专门的branch
  • develop 在第一时间从 master 上分离出来
  • 需要开发任何功能的时候,从 develop 创建出新的 feature branch,开发完成后合并回 develop(合并的时候使用 --no-ff),然后删掉 feature branch
  • 当下一正式版本需要的所有功能开发完成之后,从 develop 上创建新的 release branch,并在 release branch 合并到 master 后合并回develop(合并的时候用 --no-ff),然后删掉 release branch

feature branches

  • 功能型开发分支(目的型分支)
  • 始于develop,终于develop,每次开发新功能是从 develop 创建,开发完成后合并到 develop(使用 --no-ff),然后被删掉

release branches

  • 预交付分支(目的型分支)
  • 始于develop ,终于master & develop
  • 每次下一版本的功能开发完毕后,从 develop 上创建
  • 创建完成后,更新版本号,然后单独做一个新的 commit
  • 如果有 bug fix,直接在 release branch 上修复,bug fix 完成后,合并到 master 和 develop(使用 --no-ff),然后 release branch 被删掉

hotfix branches

  • 热修复分支(目的型分支)
  • 始于master,终于master & develop
  • 已正式发布的产品发现 bug,直接从 master 或者出问题的 tag 上创建 hotfix branch 进行紧急修复,修复完成后合并到 master 和 develop(或 release branch 如果有的话)(使用 --no-ff),然后被删掉。

这里还有一个点,如果是本地创建的 feature 分支(从develop分支创建)开发完成后,成功合并到 develop 分支后,这个本地 feature 分支是可以删掉的,并不一定要提交到远程,不然远程仓库里会有很多冗余分支。

Git 配置

首先需要下载Git客户端:https://git-scm.com/

然后输入下面命令进行配置(主要是用户名信息):

bash 复制代码
# 设置提交代码时的用户信息
git config [--global] user.name "[name]"               # 配置用户名
git config [--global] user.email "[email address]"     # 配置邮件
git config --list          # 显示当前的Git配置
git config -e [--global]   # 编辑Git配置文件

Git的设置文件为.gitconfig,它可以在用户主目录下(全局配置),也可以在项目目录下(项目配置)

生成 RSA 密钥 SSH Key

bash 复制代码
ssh-keygen -t rsa
cat ~/.ssh/id_rsa.pub  

第一次使用该命令时,之后会在用户目录下生成.ssh文件夹(如果是windows就是在C:/Users/用户名/目录下, 如果是Mac就用上面的cat命令查看即可),其中会包括:id_rsa、id_rsa.pub以及其他的文件,其中 id_rsa 是私钥,id_rsa.pub 是公钥。

将id_rsa.pub公钥文件中的内容全部复制,以使用 gitlab 仓库为例,打开gitlab,找到Profile Settings --> SSH Keys ---> Add SSH Key,把复制的内容粘贴到Key所对应的文本框,在Title对应的文本框中给这个sshkey设置一个名字,点击Add key按钮。


检测是否配置成功:本地 git-bash 输入以下命令

bash 复制代码
$ ssh -T git@github.com

若显示如下,则代表配置成功:

绑定成功了之后,就可以复制 gitlab上面项目的 ssh 地址进行 git clone ,将 gitlab上项目克隆到本地了:

gitlab 上还可以添加项目成员和设置权限:

访问权限

  • Private - 私有,只有属于该项目成员才能clone
  • Internal - 内部,有Gitlab账号的人都可以clone
  • Public - 公开,任何人可以clone

行为权限

  • Guest - 访客
  • Reporter - 报告者; 可以理理解为测试员、产品经理理等
  • Developer - 开发者
  • Master - 主人,负责对Master分⽀支进行维护
  • Owner - 拥有者

git 克隆项目时使用 HTTPS url 跟 SSH url 的区别:

  • 使用 https url 克隆对初学者来说会比较方便,复制 https url 然后到 git Bash 里面直接用 clone 命令克隆到本地, 但是每次fetch和push代码都需要输入账号和密码,这也是https方式的麻烦之处。
  • 而使用 SSH url 克隆却需要在克隆之前先配置和添加好SSH key,因此,如果你想要使用SSH url克隆的话,你必须是这个项目的拥有者(或者你的项目的主管有权限添加SSH key)。否则你无法添加SSH key,另外 ssh 默认每次fetch和push代码不需要输入账号和密码 ,如果你想要每次都输入账号密码才能进行fetch和push也可以另外进行设置。

Git 命令速查表

这个图上的命令不全,这里有一个总结的比较全面的帖子:Git常用命令,总结的很全了!

相关推荐
Winlifes5 天前
我给 Codex 做了一个 Git 面板:分支树、提交历史和工作区操作
git
郑州光合科技余经理6 天前
同城外卖小程序开发:下单成功后,后台导出能不能对上用户端状态
开发语言·前端·git·后端·uni-app·php·ai编程
我命由我123456 天前
Git 推送报错:error: src refspec main does not match any
运维·git·gitee·github·运维开发·学习方法·版本控制
Lcr3s6 天前
Git基础之(0):如何在Ubuntu(Linux)上安装git
git
玄芯散人7 天前
【筑基·058】Git协作工作流:冲突解决和PR流程
git·版本控制·团队协作
寺中人7 天前
Git 版本控制完全入门指南:从安装到实战,提交 + 分支 + 协作 + 冲突解决全拆解
git·开发工具·版本控制·团队协作·代码管理
荔枝梅梅7 天前
新手程序员 SSH 第一课:从 Git 仓库连接失败理解 SSH 协议与密钥配置
git
玄芯散人7 天前
【筑基·057】Git代码时光机:版本控制入门到分支管理
git·版本控制·嵌入式开发
szephyr7 天前
Git 分支管理实战:feature/release/hotfix 怎么用才不乱
git·分支管理·团队协作·工作流·hotfix
一木 之林7 天前
手搓家庭服务器:二手装机、Docker部署、端口映射与frp内网穿透
服务器·人工智能·git·编辑器