查看仓库状态和文件更改
查看工作区状态:
git status
与最近的一次add或commit比较文件的不同:git diff
查看该文件与commit库中版本的变动情况:git diff HEAD --
查看过修改内容后,提交修改和提交新文件是一样的操作:git add
,在git commit
之前随时都可以用git status
确认当前仓库的状态。
第三条命令在add过一次修改到缓存区后用。新到旧顺序:工作区、缓存区(add)、版本库(commit)
版本回退
回退到某版本:
git reset --hard commit_id
向上回退n个版本:git reset --hard HEAD~{int n}
。
查看commit历史:git log
简短查看commit历史:git log --oneline
要重回reset前的版本:git reflog
,查看HEAD
变动的历史记录,以确定要回到未来的版本号。
HEAD指向的commit版本就是当前正在操作的commit版本,commit历史记录由上新下旧排列。
撤销修改
撤销工作区修改:
git checkout --
撤销add
到暂存区的修改:git reset HEAD
(似乎是返回到了再上一次git add
的状态)。
checkout
用于将工作区的文件撤销到上一次git add
或git commit
时的状态,丢弃本地修改。
删除文件
当已经commit后,本地工作区删掉了某些文件时,git status
会提示有哪些文件相对于上一个版本被删除了,此时有两种选择:
从版本库中删除文件:
git rm
用版本库的文件替换掉工作区的文件:git checkout --
本地没删错时,git rm
,并git commit
修改版本库状态。
删错文件时,用git checkout --
把误删的文件还原到之前commit的状态,命令中一定记得加--
,否则就是切换分支的命令了。
分支操作
查看分支:
git branch
创建分支:git branch
切换分支:git checkout
创建+切换分支:git checkout -b
合并某分支到当前分支:git merge
非Fast forward
合并:git merge --no-ff -m
删除分支:git branch -d
克隆仓库:git clone [email protected]:
/ .git
推送到远程分支(远程分支不存在将自动创建):git push origin local_branch:remote_branch
或git push origin branch-name
查看远程分支:
git remote -v
创建远程分支到本地:git checkout -b
origin/
获取远程分支git fetch origin
关联本地与远程分支:git branch --set-upstream-to=origin/
删除远程分支git push origin --delete origin/
远程同步下来时,如果提示“Cannot update paths and switch to branch git fetch
,再重试。
安装后配置
$ git config --global user.name "Your Name"
$ git config --global user.email "[email protected]"
创建版本库
初始化仓库:
git init
。
添加文件:git add
添加所有文件:git add .
提交版本:git commit -m
使用Commitizen规范化commit
$ npm install -g commitizen
$ commitizen init cz-conventional-changelog --save --save-exact
add
的文件保存在暂存区(stage)
不加-m
参数会启动文本编辑器以输入本次提交的说明。按i
进入输入模式,输入内容不用带引号,输入完按esc
退出输入模式,按shift + :
进入命令模式,输入wq
保存并退出。
因为Windows下的换行符是CRLF,Linux和Mac是LF,跨平台开发时会存在问题,commit时有可能会提示:
warning: LF will be replaced by CRLF
fatal: CRLF would be replaced by LF
解决方法,修改core.autocrlf的值:
git config --global core.autocrlf true #这个是转换,也是默认值
git config --global core.autocrlf input #貌似是上库转换,从库中迁出代码不转换
git config --global core.autocrlf false #这个一般是window上的,不转换
链接github
创建ssh key:
ssh-keygen -t rsa -C "[email protected]"
添加远程库:git remote add origin [email protected]:
/ .git
关联本地与远程分支:git branch --set-upstream-to=origin/
第一次远程推送:git push -u origin master -f
非第一次推送:git push origin master
同步本地仓库:git pull --rebase origin master
远程库克隆为本地库:git clone [email protected]:
/ .git
push
时如果本地与远程文件结构差异太大,git push
后加-f
,强制覆盖已有分支。
如果提示remote origin already exists
,则先git remote rm origin
在用户主目录下,查看是否有id_rsa
(私钥)和id_rsa.pub
(公钥)这两个文件,如果没有,输入上面的命令,创建ssh key,一路回车,无需密码,之后在github的ssh key设置里将.pub的文件中内容复制粘贴过去。
pull --rebase
:如果本地库和仓库的文件不同步会提示推送失败,这时将远程仓库的文件与本地合并一下。
多人协作的流程:
- 首先,可以试图用
git push origin branch-name
推送自己的修改; - 如果推送失败,则因为远程分支比你的本地更新,需要先用
git pull
试图合并; - 如果合并有冲突,则解决冲突,并在本地提交;
- 没有冲突或者解决掉冲突后,再用
git push origin branch-name
推送就能成功
Git鼓励大量使用分支。
使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。
基础命令
使用git最基础的操作。
git-config 配置
用户配置
git config --global user.name "John EveryThing"
git config --global user.email [email protected]
配置级别
--local 默认,高优先级:只影响本仓库
--global 中优先级:影响到所有当前用户的git仓库
--system 低优先级:影响到全系统的git仓库
git-init 初始化仓库
使用git status
查看当前仓库的信息。
再使用git init
来在一个文件夹创建一个git仓库,会在此文件夹创建一个.git文件夹。
这个目录默认是隐藏的,如果没有看到.git
目录,用ls -ah
命令显示。
git-status 对状态的跟踪
git对文件的状态跟踪分内容状态和文件状态。
内容状态:工作目录、暂存区、提交区。
文件状态:未跟踪、已跟踪。
所有这些状态之间都可以相互转化。
git-add 添加跟踪文件
git add *.*
命令添加单个文件内容到暂存区,同时文件被跟踪。如果要添加当前目录下的所有文件,使用git add .
命令。
gitignore 筛选添加文件
.gitignore在添加时忽略匹配的文件,仅作用于未追踪的文件。是一个筛选列表不能用于删除已经添加上的文件。在github已经有gitignore的官方忽略文档。
git-rm 从暂存区删除文件
git rm --cached
仅从暂存区删除。
git rm
从暂存区与工作目录删除。
git rm $(git ls-files --deleted)
删除所有被跟踪,但是在工作目录被删除的文件。其中ls-files是到暂存区查找。
git-commit 从暂存区提交
git commit
命令根据暂存区内容创建一个提交记录。
git commit -m 'initial commit'
这个命令使用-m来在提交同时声明一个注释。
如果想要省略git add这一步直接提交,添加上-a参数,使用git commit -a -m 'full commit'
命令,就会从工作目录直接提交到提交区。
git-log 查看历史信息
git log
命令直接用于查看完整信息的提交历史。如果只想查看简短的配置信息,添加--oneline参数,即git log --oneline
。
如果想让查看的配置信息完整美观又简洁:
git log --color --graph --pretty=format:'%Cred%h%Creset
-%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset --abbrev-commit
git config alias 配置别名
上面的配置信息太长了,用alias命令给自己定义缩短。
$ 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"
$ git lg
git-diff 查看差异
直接使用git diff
查看工作目录与暂存区的差异。
用git diff -cached [
查看暂存区与某次提交差异,默认为HEAD(指向当前的提交),如果只是为了查看暂存区与上一次提交的差异,最后的这个参数可以不传。git diff HEAD
。
用git diff
查看工作目录与某次提交的差异,后面可以接两个参数。
git-checkout 撤销本地修改
git checkout --
将文件内容从暂存区复制到工作目录,该操作会丢弃对暂存区内容的修改,使用时要小心。
git-reset 撤销暂存区内容
git reset HEAD
将文件内容从上次提交回退到暂存区。这样的操作会造成暂存区与工作目录文件的不一致,git会提示没有用add命令添加修改后的工作目录内容到暂存区。
如皋想将内容从上次提交后在提交区的内容复制到工作目录,使用gitcheckout HEAD --
git branch分支操作
分支的增删查改都靠它。
git branch
用来创建一个分支。
加入-d参数后git branch -d
可以用来删除指定的分支。
git checkout分支
通过移动HEAD检出版本,可用于分支切换。
git checkout
切换到目标分支。
加入-b参数后git checkout -b
会创建并切换到该分支。相当于先git branch
后紧接一个git checkout
。
git checkout
移动到任何一个commit id所在的引用对象上。
想快速回到上一个分支?使用git checkout -
命令即可。
git branch -v
显示现在所有的分支信息,分支前面带星号的就是当前HEAD指针指向的分支。
当checkout到一个不是分支指针所在的commit id后,此时的HEAD指针会指向一个非分支指针指向的位置,此时的状态称为detached(分离的) head。如果HEAD处于分离状态就要尽量避免在此状态提交东西,因为没有引用会指向这个提交记录,当HEAD重新回到master分支时刚才的提交都会被视为没有做引用,最后会在垃圾回收阶段被回收。因此当HEAD处于分离状态是不要进行写操作,而只是读取它的内容。由于HEAD指向的内容可以被复制到暂存区和工作目录,这是可以查看具体提交时的信息。
git reset回退
如果要回退到其他commit版本git reset --mixed
,最后的参数如果不填就回退到上一个commit版本。这样,HEAD,master都会移动到上一个commit,同时它们指向的内容会被复制到暂存区。
当使用head模式git reset --hard
,这部分内容除了被复制到暂存区,还会被复制到工作目录。
使用soft模式git reset --soft
,只有HEAD,master移动到这个commit上,对暂存区和工作目录不会有处理。这样上一个提交没有上传,也没有任何指针指向它了,有可能会被回收,成为了一个没有被索引的提交。怎么找回它呢?使用git reflog
命令按顺序查看之前经过的所有commit路径,当前所在的位置就是列表的顶部,之前的commit会按序向下排,但是使用这个命令找回之前的commit要尽快,否则有的记录可能会丢失。
使用捷径
可以避免使用不直观的哈希值,用捷径,在下面的例子中,A表示HEAD指针,或分支名,或commit id。
A^表示A之上的父提交。A~n表示在A之前的第n次提交。
reset vs checkout
通过上面的内容可以看出reset和checkout直接有非常多的相似之处,下面列表以表示一下他们之间的区别。
git stash暂时保存
stash是一个独立在工作目录和暂存区之外的一个临时保存区。
git stash save 'push to stash area'
会保存目前的工作目录和暂存区状态,并返回到干净的工作空间,同时保存一条注释。
使用git stash list
查看stash区保存的所有信息。
然后使用git stash apply stash@{0}
恢复stash区的内容到工作目录。最后使用git stash drop stash@{0}
将stash上的记录删掉。
上面的两条操作可以合为stash pop
一条命令完成,stash pop = stash apply + stash drop.
git merge合并分支
假设当前的HEAD指向master分支,同时还有个分支名为next,使用命令git merge next
由于目前正在master分支所以省略了第二个参数,合并的结果会被复制到工作目录和暂存区,再会完成一次提交,这个提交节点的父节点有两个。来看一下这个合并后的节点的具体信息,使用git cat-gile -p HEAD
命令,会发现有两个parent commit id,而next分支没有改变。
在git merge next master
合并后有很大的几率会提示两个节点中有冲突的文件。使用git status
查看冲突的具体信息,在文件中做好修改后使用git add和git commit来解决。
假设从master分支创建了next分支,但是master分支没有向前移动仅仅是在next分支上做了修改,这时候使用git merge next
命令会将master分支指向当前操作的next分支,这样操作就会变成线性,master分支其实与next分支合并了。
如果要避免fast-forward式的合并,使用git merge next --no-ff
,这样原来的master分支会向前复制到一个新分支,并且与next分支合并。
git rebase修剪历史基线
首先现在有两个分支:master和feature
对如图所示的分支进行修剪基线操作
git rebase master
,git首先会找到两个分支节点的结束点,然后会将head所在的所有历史节点分别与master最后的节点进行合并并在master分支上依次将合并结果保存为新节点,这个过程是重演而不是复制,因为创建了2个新的节点。然后HEAD和feather分支都会指向最后的这次提交,master分支还保存在原来的位置,如下图:
然而并不是所有的变基操作都需要将原来的分支上所有节点都与master合并一次,所以这时候可以用
git rebase --onto master
这样指定feather上某个特定的节点之后的节点与master的最后一个节点合并,指定的节点在合并时就被丢弃了。如图
rebase vs merge
rebase和merge没有孰好孰坏之说,最大的区别就是合并后是否是线性的。
切勿在公有分支使用rebase,比如之前例子中的master分支,否则rebase的后果会变成这样:
这样的master就变化到feather了。
git tag别名
如果要给一个commit id 设置一个别名就可以使用git tag v0.1 e39d0b2