commit
组成commit
上会有一些 branch
指向它们,这些 branch
的本质是引用HEAD
,它始终指向当前的位置,这个位置可以是 commit
,也可以是 branch
staging
原意:舞台表演前的筹划准备(例如汇集道具和演员)。Git 中的意思:把改动内容汇集起来以待提交。staging area
:待提交的修改内容暂时存放的地方。主要用于和已经改动但不打算提交的内容区分开来。add
指令:把指定的内容放进暂存区。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] # 改名文件,并且将这个改名放入暂存区
commit
表示对于一次改动的提交,它可以代表当前时刻下 Git 仓库的完整快照,但本质上,commit
只是记录了距离上一次 commit
之间的改动。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
的含义是分支,指的是仓库结构出现分叉时的不同的「叉」branch
是引用(reference),即指向某个 commit
的指针直观感觉的 branch
:
而实质上的 branch
:
所以,branch
和你什么时候创建的它无关,也和仓库的起点无关,只和它当前指向哪个 commit
有关。
master
是⼀个特殊的 branch
,因为它是 Git 的默认 branch
(默认 branch
可以修改)。默认 branch
的特点:
clone
方法把仓库取到本地的时候,默认 checkout
出来的是默认 branch
,即 master
;push
命令把本地内容推送到远端仓库的时候,远端仓库的 HEAD
永远跟随默认 branch
,而不是和本地 HEAD
同步。换句话说,只有 push
master
分支到远端的时候,远端的 HEAD
才会移动。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
一起移动clone
是从远端仓库初次把数据取下来:git clone https://github.com/xxxx.git
clone
命令具体会做两件事:
branch
取下来,并把从初始 commit
到达这些 branch
的路径上的所有 commit
都取下来:commit
开始,向 master
指向的 commit
,一个个地把每个 commit
应用,最终得到一个「当前」状态的仓库内容,写进 Git 所在的目录(这个目录叫做 working tree)HEAD
指向的 commit
开始,倒序显示每一个 commit
的摘要信息(最新的排在最前面)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 # 显示所有提交过的用户,按提交次数排序
merge
就是合并,它会把当前 commit
和指定 commit
(所谓 commit
,可以直接用它的 hash
值来指定,例如 4a0a1b
,也可以用一个直接或间接指向它的引用来指定,例如 master
或者 HEAD
)进行合并,并把这个合并行为创建成一个新的commit
。git merge feature1 # 合并feature1分支至当前分支
git merge origin/master # 合并远程master分支至当前分支
git merge
会产生一个新的提交。
merge
行为所产生的 commit
,是一种特殊的 commit
:
commit
就好commit
,这是一般的 commit
不具有的性质git checkout master
相当于merge from master
,git merge mybranch
相当于 merge from mybranch
。
merge 冲突
当 Git 不知道怎么合并某两处冲突的修改时,会中断自动合并,并对冲突文件进行标记。解决方法:
add
来添加进暂存区git merge --continue
来继续自动合并流程origin/
打头的 branch
,它们是远端仓库(别名为origin
)的本地镜像。它们的作用是方便在本地查看远端仓库的 branch
状态。远端仓库默认名称是
origin
,但也可以给它们起别的名称
origin/
分支并不在本地直接操作,它们一般只在两种情况下会进行自动更新:
push
的时候,push
成功后,push
成功的 branch
会把它对应的 origin/
branch更新到当前 commit
(因为远端的 branch
已经随着 push
的成功而更新,所以本地镜像也一起更新)pull
或者 fetch
的时候,由于从远端拿到了所有最新的 branch
状态,所以也会一同更新所有的 origin/
branch关于
origin/HEAD
:这是一个永远跟随origin/master
的引用,它最大的作用是用来标记默认branch
git push origin feature1
具体做两件事:
HEAD
所指向的 branch
(只是一个引用哦)推送到远端仓库branch
向前回溯,远端仓库缺少的每一个 commit
也推送到远端仓库。push
的 branch
的本地镜像 origin/xxx
更新注意:
origin/HEAD
并没有在图上画出来,但如果push
是master
(即默认branch
),那么本地的origin/HEAD
也会更新到master
的最新位置;当push
的是其他branch
的时候,origin/HEAD
并不会更新。
也就是说,origin/HEAD
只和默认分支相关,和HEAD
是无关的。
git push [remote] [branch] # 上传本地指定分支到远程仓库
git push [remote] --force # 强行推送当前分支到远程仓库,即使有冲突
git push [remote] --all # 推送所有分支到远程仓库
git push origin master # 将当前分支push到远程master分支
branch
取到本地。git pull origin feature1
具体做的事有三件:
branch
的最新位置更新到本地的 origin/xxx
镜像branch
,本地所缺少的所有 commit
,也取到本地origin/当前branch
的内容合并到当前 branch
事实上,git pull origin feature1
会分成两部执行,它等价于下面两行:
git fetch
git merge origin/feature1
git fetch
的含义:
git fetch [remote] # 下载所有远程分支,但不更新本地分支(另需merge)
HEAD
,让它指向某个 commit
或某个 branch
。checkout --detach
:让 HEAD
脱离当前 branch
,直接指向下面的commit
。git checkout -b dev origin/master
从远程的 master
分支检出到本地的dev
上,并切换到新建的本地dev
分支上。
其实也是相当于两个命令的缩写:
git branch dev # 创建分支
git checkout dev # 切换分支
本地的项目中,一直都保留着一个master
分支,并关联远程的master
分支。本地的master
分支,你可以当作是个干净的主线,每次新来一个需求的时候你都可以以该分支为基准,新建一个分支进行开发,最后进行合并,并由这个基准分支(本地master
)提交到远程;具体的专业信息你可以参照文档:Git-分支-分支的新建与合并
通过 checkout
可以恢复指定文件(如不小心commit
掉的)到工作区(未提交状态):
git checkout [file] # 恢复暂存区的指定文件到工作区
git checkout [commit] [file] # 恢复某个commit的指定文件到暂存区和工作区
git checkout . # 恢复暂存区的所有文件到工作区
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文件(可用于修改错误回退)
commit
(以及它之前的 commits
)应用到指定的需要 rebase
的 commit
上。Git 中的每一个
commit
都是不会改变的,所以rebase
之后的每个commit
都是新产生的,而不是对原先的commit
进行「修改」
rebase 冲突
rebase
的冲突解决方法和 merge
冲突一样,只是把 git merge --continue
改成 git rebase --continue
就行了。
branch
指向指定的 commit
。git reset [指定commit] # 重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变
移动到指定 commit
,并保留 working tree 的内容。
git reset --hard [指定commit]
移动到指定 commit
,并重置 working tree。
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 # 列出所有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
指向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
到远端可以创建一个新分支(也可以不提交)。
git push [remote] [tag] # 提交指定tag
git push [remote] --tags # 提交所有tag
git checkout -b [branch] [tag] # 新建一个分支,指向某个tag
git push origin :refs/tags/[tagName] # 删除远程tag
push
到 master
的内容需要删除。它的原理是创建一个新的commit
,内容是指定 commit
的「相反内容」。# 新建一个commit,用来撤销指定commit 后者的所有变化都将被前者抵消,并且应用到当前分支
git revert [commit]
commit
,合并进当前分支。 将 commit
到 HEAD
处。git cherry-pick [commit1] [commit2]
git cherry-pick ff44785404a8e # 合并提交ff44785404a8e的修改
⽐如我想抛弃某个 branch
,这个特性不要了,但它的某两个 commit
我希望保留。
git reflog <branch>
查看指定的引用(HEAD
或 branch
)的移动历史,从而找到之前的某个特定 commit
merge
到 master
去merge
:由于别人可能在你之前 push
过,所以你的 push
可能失败。所以通常会需要先 pull
一下,然后再 push
。pull request,
在同事审阅完成之后,通过按钮实现在线 merge
pull request
是什么:是开发者对远端仓库的提出的「拉取某个 branch
」的请求两条持久主线: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客户端:https://git-scm.com/
然后输入下面命令进行配置(主要是用户名信息):
# 设置提交代码时的用户信息
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
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 输入以下命令
$ ssh -T [email protected]
若显示如下,则代表配置成功:
绑定成功了之后,就可以复制 gitlab上面项目的 ssh 地址进行 git clone ,将 gitlab上项目克隆到本地了:
gitlab 上还可以添加项目成员和设置权限:
访问权限
行为权限
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常用命令,总结的很全了!