目录
初始化仓库
#初始化一个Git仓库,使用git init命令即可将当前目录文件夹变成Git可以管理的仓库。
#创建git仓库的本地文件夹即为工作区,创建完毕后其中多了.git文件夹,代表Git的版本库
git init
工作区&暂存区&分支仓库&远程仓库
工作区:就是在电脑里能看到的目录
暂存区:工作区有一个隐藏目录.git
,这个不算工作区,而是Git的版本库。Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master
,以及指向master
的一个指针叫HEAD
。Git的版本库(.git文件夹)里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git自动创建的第一个分支master,以及指向master的一个指针叫HEAD;
添加文件
#添加文件到Git仓库,分两步:使用命令,注意,可反复多次使用,添加多个文件,实际是添加到暂存区。当用#git add命令后,在工作区的修改被放入暂存区,准备提交。
git add <file>
git commit -m <message>
#使用命令,message是本次提交的说明,最好是有意义的。Git跟踪并管理的是修改,而非文件,git commit只负责把暂存区的修改提交,未add到暂存区的修改不会被提交。
状态管理
#要随时掌握工作区的状态,使用如下命令
git status
#如果git status显示有文件被修改过,用下面命令
git diff
回滚
若推送的分支已经合并到主分支,这时想回滚代码可用git revert命令,本质是用某次commit的代码再做一次提交,不会对已存在的代码产生影响;例如合入主分支的commit id是aaaaaa,只需要拉取最新的主分支,然后新建分支,执行git revert aaaaaa,再推送到远程,合回主分支即可。
版本回退
#版本回退使用如下命令,HEAD是指向当前版本的commit_id,也就是最新的提交,
git reset --hard commit_id
#上一个版本就是HEAD^,上上一个版本就是HEAD^^,往上100个版本写100个^
#容易数不过来,所以写成HEAD~100。
git reset --hard HEAD~1
#撤销中间某次commit
git revert commit_id
#撤销中间某次合并的commit
git revert -m commit_id
#PS:git revert 失败报错:error: option `mainline' expects a number greater than zero、error: Commit faulty merge is a merge but no -m option was given、
git revert -m 1 commit_id
#版本回退前,用可以查看提交历史,以便确定要回退版本的commit_id,
#--pretty参数使每个版本输出一行,--graph参数可以查看分支合并图。
git log --pretty=oneline --graph
#要重返未来,先查看命令历史,以便确定要回到未来版本的commit_id。
git reflog
撤销修改
#场景1:当改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,
#用以下命令;git checkout其实是用暂存区的版本替换工作区的版本,
#无论工作区是修改还是删除,都可以“一键还原”,
#其中的--很重要,没有--,就变成了“切换到另一个分支”的命令。
git checkout -- filename
#场景2:当不但改乱了工作区某个文件的内容,还add到了暂存区时,想丢弃修改,分两步,
git reset HEAD <file> //第一步回到场景1
git checkout -- filename //第二步按场景1操作
#场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,
#参考版本回退一节,不过前提是没有推送到远程库。
git reset的三种模式
区别:
-
--hard:重置位置的同时,直接将 working Tree工作目录、 index 暂存区及 repository 都重置成目标Reset节点的內容,所以效果看起来等同于清空暂存区和工作区。
-
--soft:重置位置的同时,保留working Tree工作目录和index暂存区的内容,只让repository中的内容和 reset 目标节点保持一致,因此原节点和reset节点之间的【差异变更集】会放入index暂存区中(Staged files)。所以效果看起来就是工作目录的内容不变,暂存区原有的内容也不变,只是原节点和Reset节点之间的所有差异都会放到暂存区中。
-
--mixed(默认):重置位置的同时,只保留Working Tree工作目录的內容,但会将 Index暂存区 和 Repository 中的內容更改和reset目标节点一致,因此原节点和Reset节点之间的【差异变更集】会放入Working Tree工作目录中。所以效果看起来就是原节点和Reset节点之间的所有差异都会放到工作目录中。
使用场景:
-
--hard:(1) 要放弃目前本地的所有改变時,即去掉所有add到暂存区的文件和工作区的文件,可以执行 git reset -hard HEAD 来强制恢复git管理的文件夹的內容及状态;(2) 真的想抛弃目标节点后的所有commit(可能觉得目标节点到原节点之间的commit提交都是错了,之前所有的commit有问题)。
-
--soft:原节点和reset节点之间的【差异变更集】会放入index暂存区中(Staged files),所以假如我们之前工作目录没有改过任何文件,也没add到暂存区,那么使用reset --soft后,我们可以直接执行 git commit 將 index暂存区中的內容提交至 repository 中。为什么要这样呢?这样做的使用场景是:假如我们想合并「当前节点」与「reset目标节点」之间不具太大意义的 commit 记录(可能是阶段性地频繁提交,就是开发一个功能的时候,改或者增加一个文件的时候就commit,这样做导致一个完整的功能可能会好多个commit点,这时假如你需要把这些commit整合成一个commit的时候)時,可以考虑使用reset --soft来让 commit 演进线图较为清晰。总而言之,可以使用--soft合并commit节点。
-
--mixed(默认):(1)使用完reset --mixed后,我們可以直接执行 git add 将這些改变果的文件內容加入 index 暂存区中,再执行 git commit 将 Index暂存区 中的內容提交至Repository中,这样一样可以达到合并commit节点的效果(与上面--soft合并commit节点差不多,只是多了git add添加到暂存区的操作);(2)移除所有Index暂存区中准备要提交的文件(Staged files),我们可以执行 git reset HEAD 来 Unstage 所有已列入 Index暂存区 的待提交的文件。(有时候发现add错文件到暂存区,就可以使用命令)。(3)commit提交某些错误代码,或者没有必要的文件也被commit上去,不想再修改错误再commit(因为会留下一个错误commit点),可以回退到正确的commit点上,然后所有原节点和reset节点之间差异会返回工作目录,假如有个没必要的文件的话就可以直接删除了,再commit上去就OK了。
删除文件
#确实要从版本库中删除该文件,也分两步,先用命令git rm删掉,再git commit
git rm <filename>
git commit -m “remove filename”
#注意,这两步操作之后,工作区中的文件也会被删除!!!
远程仓库
#关联远程仓库,关联一个远程库时必须给远程库指定一个名字,origin是默认习惯命名;
git remote add origin git@server-name:path/repo-name.git
//在远程版本库建立一个与本地分支相同的远程分支,以后每次推送直接git push即可
git push --set-upstream origin feature/pushtest
#关联后,首次推送master分支的所有内容:
git push -u origin master
#此后,每次本地提交后,只要有必要,就可以使用以下命令推送最新修改;
git push origin master
#克隆仓库,Git支持多种协议,ssh协议速度最快 --recursive拉取子模块
git clone --recursive git@github.com:GYE19970220/gitskills.git
#从指定远程分支clone
git clone -b <name> git@github.com:GYE19970220/gitskills.git
#从指定远程tag clone
git clone -b <tag number> git@github.com:GYE19970220/gitskills.git
分支管理
开发一个新feature,最好新建一个分支
#创建dev分支:
git branch dev
#切换到dev分支:
git checkout dev
git switch dev
#创建并切换到dev分支:
git checkout -b dev
git switch -c dev
#以上命令默认从当前分支创建,下面的命令从远程仓库的dev分支创建
git checkout -b dev origin/dev
#从指定远程tag创建分支
git checkout -b dev_1.2.10.1 1.2.9.1
#查看当前分支:
git branch
#合并指定分支dev到当前分支,合并分支时,默认是fast forward模式,
#加上--no-ff参数就可以用普通模式合并,普通模式合并后的历史有分支,
#能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。
git merge dev --no-ff
#合并某个分支改动的到当前分支:
git cherry-pick <commit_id>
#删除分支dev:
git branch -d dev
#如果要删除一个没有被合并过的分支,可以通过以下命令强行删除
git branch -D <name>
#当手头工作没有完成时,先把工作现场git stash一下,
#然后去重拉分支干别的事情,干完后,再git stash pop,回到工作现场
#保存工作现场:
git stash
#查看stash存的所有现场
git stash list
#回到工作现场
git stash pop
git stash pop stash@{0}
#只想复制commit 4c805e2这个提交所做的修改,并不是把整个master分支merge过来
git cherry-pick 4c805e2
#查看远程库详细信息:
git remote -v
#推送分支:例如 git push origin master
git push <远程仓库名> <本地分支名>
多人协作
#首先,可以试图推送自己的修改
git push origin <branch-name>
#如果推送失败,则因为远程分支比你的本地更新,需要先保存现场,
git stash
#然后拉一下新的远程分支
git pull
#如果git pull失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接
git branch --set-upstream-to=origin/dev dev
#然后重新git pull
#再恢复现场
git stash pop
#如果合并有冲突,则解决冲突,并在本地commit;
#没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!
并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?
-
master
分支是主分支,因此要时刻与远程同步; -
dev
分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步; -
feature分支是否推到远程,取决于是否和小伙伴合作在上面开发。
总之,就是在Git中,分支完全可以在本地自己藏着玩,是否推送,视心情而定!
标签管理
#新建一个标签,默认为HEAD,也可以指定一个commit id;
git tag <tagname>
#指定标签信息;
git tag -a <tagname> -m "blablabla..."
#查看所有标签。
git tag
#推送一个本地标签;
git push origin <tagname>
#推送全部未推送过的本地标签;
git push origin --tags
#删除一个本地标签;
git tag -d <tagname>
#删除一个远程标签。
git push origin :refs/tags/<tagname>
使用Github
-
在GitHub上,可以任意Fork开源仓库;
-
自己拥有Fork后的仓库的读写权限;
-
可以推送pull request给官方仓库来贡献代码。
-
忽略某些文件时,需要编写
.gitignore
; -
.gitignore
文件本身要放到版本库里,并且可以对.gitignore
做版本管理!
致谢
文章内容几乎都来自廖雪峰老师的Git教程,感谢,侵权删。