前言
1.git结构
git的三个区
工作区(Working Directory)
暂存区
版本库(Repository)
2.一个版本库可以有多个分支,一个分支有多个提交版本
一.本地仓库的操作
1.git配置
git config --global user.name gaowenlong
git config --global user.email gaowenlongsd@gmail.com
需要注意的是:用了 git config命令的--global参数就表示这台电脑上的所有仓库都是使用这个配置
2.创建本地仓库
首先,选择一个合适的地方,创建一个空目录:
$ mkdir learngit
$ cd learngit
$ pwd (pwd命令用于显示当前目录)
/Users/michael/learngit
第二步,通过git init命令把这个目录变成Git可以管理的仓库:
$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/
当前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。
如果你没有看到.git目录,那是因为这个目录默认是隐藏的,用ls -ah命令就可以看见。
3.将修改保存到版本库
git add <file> (将指定文件的修改添加到暂存区,例:$ git add readme.txt)
git add . (将所有文件的修改添加到暂存区)
$ git rm <file> (删除暂存区的指定文件,同时删除工作区的文件.此时想恢复可使用git reset HEAD <filename>,必须指明HEAD,再用git checkout <filename> 非删除时可只用git reset <filename>)
git commit -m "comment content" (将暂存区的修改添加到版本库的当前分支)
4.查看工作区和暂存区的修改状态
$ git status (可查看当前的分支,工作区和暂存区的状态)
5.查看修改内容(查看的是工作区相对于暂存区的不同)
git diff (查看所有文件的修改)
git diff <file>(查看某个文件的修改)
6.查看当前分支的提交历史(以便确定要切换到哪个版本)
git log
git log --pretty=oneline
7.查看命令历史
git reflog
8.版本切换
git reset --hard commit_id(commit_id可以为版本号的前几位,只要能唯一确定版本就行)
(HEAD指向的版本就是当前版本,可用HEAD和^指定当前版本前的版本)
(HEAD严格来说不是指向提交,而是指向当前分支名,而分支名指向当前的提交点。
所以用HEAD指向分支名,就能确定当前分支,以及当前分支的提交点:)
例子:
$ git reset --hard HEAD^(切换到当前版本的上一个版本)
$ git reset --hard 3628164(切换到版本号以3628164开头的版本)
注意:git reset --hard 和git reset的区别
git reset --hard 即恢复暂存区也恢复工作区到指定版本或指定文件
git reset 只恢复暂存区而不恢复工作区
未指定版本号的时候表示恢复到当前版本
指定版本号的时候表示恢复到指定版本
个人对git reset的理解(有--hard时,工作区和暂存区都恢复,没有--hard时,只恢复暂存区,而不恢复工作区,操作对象是当前分支的提交版本)
git reset 将暂存区的所有文件恢复到版本库的当前版本,而工作区内容不变
git reset --hard 将暂存区和工作区的所有文件都恢复到版本库的当前版本
git reset <file> 将暂存区的指定文件恢复到版本库的当前版本,而工作区内容不变
此命令错误,--hard 后只能有版本号,不能有路径。git reset --hard <file>
git reset commitid 将暂存区的所有文件恢复到版本库的指定版本,而工作区内容不变(HEAD指针变化)
git reset --hard commitid 将暂存区和工作区的所有文件都恢复到版本库的指定版本
git reset commitid <file> 将暂存区的指定文件恢复到版本库的指定版本,而工作区内容不变(HEAD指针不变)
此命令错误,--hard 后只能有版本号,不能有路径。git reset --hard commitid <file>
实际应用举例
场景:本地最新提交已经推送到远程,此时想删除远程的最后一次提交
首先需要本地回退到最后一次提交之前的版本
git reset --hard HEAD^
然后推送到远程(-f 参数是强制提交,因为reset之后本地库落后于远程库一个版本,因此需要强制提交。)
git push -f
git revert 命令意思是撤销某次提交。它会产生一个新的提交,虽然代码回退了,但是版本依然是向前的,所以,当你用revert回退之后,所有人pull之后,他们的代码也自动的回退了。
但是,要注意以下几点:
revert 是撤销一次提交,所以后面的commit id是你需要回滚到的版本的前一次提交
使用revert HEAD是撤销最近的一次提交,如果你最近一次提交是用revert命令产生的,那么你再执行一次,就相当于撤销了上次的撤销操作,换句话说,你连续执行两次revert HEAD命令,就跟没执行是一样的
使用revert HEAD~1 表示撤销最近2次提交,这个数字是从0开始的,如果你之前撤销过产生了commi id,那么也会计算在内的。
如果使用 revert 撤销的不是最近一次提交,那么一定会有代码冲突,需要你合并代码,合并代码只需要把当前的代码全部去掉,保留之前版本的代码就可以了.
git revert 命令的好处就是不会丢掉别人的提交,即使你撤销后覆盖了别人的提交,他更新代码后,可以在本地用 reset 向前回滚,找到自己的代码,然后拉一下分支,再回来合并上去就可以找回被你覆盖的提交了。
---------------------
作者:喵了个布娜娜
来源:CSDN
原文:https://blog.csdn.net/wuhounuanyangzhao/article/details/79816171
版权声明:本文为博主原创文章,转载请附上博文链接!
9.工作区的恢复
git checkout -- file (将工作区的修改恢复到暂存区,有--时只表示文件名而不表示分支名)
git checkout file (同上)
checkout的总结
(1). git checkout [-q] [<commit>] [--] <paths> ...
(2). git checkout [<branch>]
(3). git checkout [-m] [ [-b | -- orphan ] <new_branch>] [start_point]
checkout 最长用的主要有2类
一类是后面加文件,此时HEAD指针不变,主要用于对工作区内容的恢复
另一类后面加分支,此时HEAD指针变化,主要用于创建和切换分支
后加版本号,此时HEAD指针变化,用于切换版本号,进入游离状态
后加文件的命令
git checkout --filename 当没有提交版本号时将工作区的内容恢复到暂存区的状态
git checkout <commit> --filename 当有提交版本号时,表示将工作区和暂存区都恢复到版本库指定提交版本的指定文件的状态,此时HEAD指针不变,此时的状态相当于把工作区的内容修改到指定版本的文件内容后,再把修改的内容添加到暂存区。因此git checkout <commit> --filename后,可以直接执行git commit而不需要先执行git add
git checkout <commit> 若只有提交版本号,而没有指定文件时,则为切换版本号,工作区和暂存区都恢复到版本库指定版本的状态,此时HEAD指针指向指定版本,
后加分支的命令
git checkout <branch_name> 切换分支
git checkout -b <branch_name> 创建并切换分支(当没有提交版本号时,以当前commit创建新分支)
git checkout -b <branch_name> <commit> 创建并切换分支(当有提交版本号时,以某个commit创建新分支)
git checkout --orphan <branch> 基于当前所在分支新建一个赤裸裸的分支,没有任何的提交历史,但是当前分支的内容一一俱全。
新建的分支,严格意义上说,还不是一个分支,因为HEAD指向的引用中没有commit值,只有在进行一次提交后,它才算得上真正的分支。
后没有参数时,表示核查工作区相对于版本库修改过的文件
git checkout
二.远程仓库的操作
1.公钥创建
创建SSH Key。
在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:
$ ssh-keygen -t rsa -C "youremail@example.com"
如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。
2.添加公钥
登陆GitHub,打开“Account settings”,“SSH Keys”页面:
然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:
为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。
当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。
最后友情提示,在GitHub上免费托管的Git仓库,任何人都可以看到喔(但只有你自己才能改)。所以,不要把敏感信息放进去。
3.本地仓库关联远程仓库
git remote add origin git@server-name:path/repo-name.git
远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。
4.本地版本库的当前分支的所有内容推送到远程库上:
$ git push -u origin <分支名(如master)> (实际上是把当前分支推送到远程master分支上。)
当把本地有而远程没有的分支推送到远程仓库时(即本地分支第一次推送到远程时),
加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,
在以后的推送或者拉取时就可以简化命令。
git push 或者 git push origin master
git pull 或者 git pull origin master
本地分支推送到远程的总结
当本地有分支而远程没有分支时,可通过以下方法在远程建立分支
git push origin local_branch:remote_branch 将本地指定分支local_branch推送到远程库origin,远程分支名为remote_branch,但不建立本地分支与远程分支的连接
git push -u origin local_branch:remote_branch 将本地指定分支local_branch推送到远程库origin,远程分支名为remote_branch,同时建立本地分支与远程分支的连接
:前的local_branch为指定要推送的本地分支名,而:后为推送到远程后的分支名。若没有指定本地分支名,则默认将本地当前分支推送到远程
git push origin remote_branch (注意不要写成origin/remote_branch) 将本地当前分支推送到远程库origin,远程分支名为remote_branch,但不建立本地分支与远程分支的连接
git push -u origin remote_branch (注意不要写成origin/remote_branch) 将本地当前分支推送到远程库origin,远程分支名为remote_branch,同时建立本地分支与远程分支的连接
当本地有分支而远程也有分支,且本地分支与远程分支已经建立连接时
推送与拉取可直接使用git push和git pull,而不需要指定远程库和远程分支名
git push (操作的是当前的分支)
git pull
当本地有分支而远程也有分支,但本地分支与远程分支没有建立连接时
推送必须指定远程库和远程分支名
git push origin remote_branch(若远程没有分支则新建远程分支,若远程已有分支,则更新分支)
5.克隆远程仓库到本地
$ git clone <远程仓库地址(例如:git@github.com:michaelliao/gitskills.git)>
注意:克隆后是克隆的整个仓库文件夹。若想进一步对执行其他git命令,需要先进入仓库目录($ cd gitskills)
当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin
总结:
(1)git clone适用于先有远程仓库,再想在本地创建对应关联仓库的情况
(2)若先有了本地仓库,而没有远程仓库,再想建立关联的远程仓库时,可以现在远程建立一个空的新仓库,
再把本地仓库关联到远程仓库(git remote add origin <远程仓库地址(如git@server-name:path/repo-name.git)>)
然后把本地的分支推送到远程($ git push -u origin <分支名(如master)>)
6.关于git的协议
Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。
使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https。
7.查看远程库的信息
$ git remote
origin (origin 为远程库的名称)
$ git remote -v (显示更详细的信息)
origin git@github.com:michaelliao/learngit.git (fetch)
origin git@github.com:michaelliao/learngit.git (push)
分析:
origin 为远程服务器起的名
https://github.com/gaobir/localtoremont.git 为远程服务器域名
8.删除远程库名
git remote remove <远程库名>
例:git remote remove origin
9.添加远程库(或者说将本地仓库与远程仓库建立连接)
git remote add <远程库名> <远程库地址(域名)>
例:git remote add origin https://github.com/gaobir/localtoremont.git
三.仓库分支的操作
1.查看分支
查看本地分支
git branch (其中以*开头的为当前分支)
查看远程分支
git branch -r (remote)
同时查看本地和远程的分支
git branch -a (all)
远程分支将红色显示
查看本地分支及其当前提交
git branch -v
查看本地分支和远程分支的关联
git branch -vv
查看到分支合并图
git log --graph
2.创建分支
创建本地分支
①git branch <新分支名> (以本地当前分支创建新分支,但不切换到新分支)(在本地仓库的当前分支的当前提交点上创建分支)
②git checkout -b <新分支名>(以本地当前分支创建新分支,并切换到新分支,如果已经存在则报错)
③git checkout -B <新分支名>(以本地当前分支创建新分支,并切换到新分支,如果已经存在则强行覆盖)
④git branch <新分支名> <远程分支名> (以指定远程分支创建本地分支,但不切换到新分支,且远程分支与本地分支不关联)(例子:git branch develop develop)
⑤git branch <新分支名> <远程库名/远程分支名> (以指定远程分支创建本地分支,但不切换到新分支,远程分支与本地分支关联)(例子:git branch develop origin/develop)
注意:④和⑤的区别在于④没指定远程库而⑤指定了远程库,不指定远程库只创建不关联,指定了远程库则创建后关联
⑥git checkout -b <新分支名> <远程分支名> (以指定远程分支创建本地分支,且切换到新分支,且远程分支与本地分支不关联)(例子:git checkout -b develop develop)
⑦git checkout -b <新分支名> <远程库名/远程分支名> (以指定远程分支创建本地分支,且切换到新分支,远程分支与本地分支关联)(例子:git checkout -b develop origin/develop)
注意:④和⑤的区别在于④没指定远程库而⑤指定了远程库,不指定远程库只创建不关联,指定了远程库则创建后关联
3.切换本地分支
git checkout <分支名>
当分支名在本地已经存在时,则直接切换到本地分支
当分支名在本地不存在时,则以远程库的分支创建本地分支,同时本地分支和远程分支建立关联,并切换到新分支
4.创建本地新分支同时切换到新分支
git checkout -b <新分支名>
5.删除本地分支
git branch -d <分支名> (注意:删除指定分支时,必须先切换到其他分支,而且已经被合并)
git branch -D <分支名> (当要删除未合并分支时,需要强行删除,用大写的D)
删除远程分支
git push origin --delete <branchName>
6.合并分支(合并指定分支到当前分支)
git merge <name>
通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。
$ git merge --no-ff -m "merge with no-ff" dev
7.当当前分支工作到一半并且无法提交,而此时必须切换到其他分支进行其他工作时,可使用
$ git stash保存当前分支工作状态,
当其他分支的工作完成后,可使用$ git stash pop或git stash apply来恢复出存前的状态
$ git stash pop 恢复的同时把stash内容也删
$ git stash apply 恢复后,stash内容并不删除,你需要用git stash drop来删除或者使用' git stash clear '来将栈清空;
例子:
$ git stash apply stash@{0}
$ git stash apply stash@{1}
8.当前的Git栈信息
git stash list
9.推送分支到远程
$ git push origin <分支名(如master)> (当前本地分支与远程分支未建立连接时使用,当然,即使已建立了连接也可以使用,但使用git push 更方便)
$ git push (当前本地分支与远程分支建立了连接时,可以只使用git push。使用git branch -vv来查看本地分支与远程分支的连接)
$ git push -u origin <分支名(如master)>(多了-u 参数,表示想远程推送分支的同时建立连接,主要在本地建立新分支,第一次推送到远程时用。
如果没有-u,表示只推送,但不建立连接。)
git branch -u origin/branch-name 与git push -u origin branch-name(注意此处origin与branch-name见使用空格分割而不是/)
前者将本地当前分支与远程指定分支关联
后者将当前分支推送到远程指定分支,同时与远程建立关联
10.拉取远程分支(如果没有建立连接,需要指定远程库和远程分支名)
git pull <remote> <branch>(本地当前分支未与远程分支建立连接时使用,若已经建立连接,直接使用git pull即可)
git pull (在本地当前分支已经建立远程连接的前提下使用,否则会提示失败。失败时,可用建立连接后再用,或使用上面的命令)
11.将本地分支与远程分支建立连接
方法1(将被废弃)
git branch --set-upstream <本地分支名,如dev> <远程仓库名,如origin>/<远程分支名,如dev>
如果不指定本地分支名,表示将本地当前分支与远程分支建立连接
git branch --set-upstream branch-name origin/branch-name(将被废弃)
git branch --set-upstream origin/branch-name(将被废弃)
方法2
git branch --set-upstream-to=<远程仓库名,如origin>/<远程分支名,如dev> <本地分支名,如dev>
将本地已经存在的分支(或当前分支)与远程已经存在的分支进行关联
git branch --set-upstream-to=origin/feature feature
方法3
git branch -u origin/feature feature
方法4(创建新分支时使用)
创建本地新分支与远程已经存在的分支进行关联(若本地已经存在该分支或远程分支不存在会报错)
git branch --track bar origin/master
12.将本地分支与远程分支删除连接
git branch --unset-upstream <本地分支名>
13.重命名本地分支
git branch -m oldbranchname newbranchname
四.标签管理
发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。
Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。
tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起。
1.创建标签
git tag <name> 用于新建一个标签,默认为HEAD,也可以指定一个commit id;
$ git tag v1.0
$ git tag v0.9 6224937
创建带有说明的标签,用-a指定标签名,-m指定说明文字:
$ git tag -a v0.1 -m "version 0.1 released" 3628164
还可以通过-s用私钥签名一个标签:
$ git tag -s v0.2 -m "signed version 0.2 released" fec145a
签名采用PGP签名,因此,必须首先安装gpg(GnuPG),如果没有找到gpg,或者没有gpg密钥对,就会报错:
2.查看所有标签。
git tag
3.删除标签
$ git tag -d v0.1
删除远程标签
$ git tag -d v0.9(先删除本地标签)
$ git push origin :refs/tags/v0.9(再用push删除远程标签)
4.要推送某个标签到远程
git push origin <tagname>
$ git push origin v1.0
一次性推送全部尚未推送到远程的本地标签
$ git push origin --tags
五.自定义git
1.忽略特殊文件
忽略某些文件时,需要编写.gitignore;
.gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理!
忽略文件的原则是:
(1)忽略操作系统自动生成的文件,比如缩略图等;
(2)忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
(3)忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。
不需要从头写.gitignore文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:
https://github.com/github/gitignore
.gitignore的内容例子:
# the composer package lock file and install directory
# Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
# /composer.lock
/fuel/vendor
# the fuelphp document
/docs/
# you may install these packages with `oil package`.
# http://fuelphp.com/docs/packages/oil/package.html
# /fuel/packages/auth/
# /fuel/packages/email/
# /fuel/packages/oil/
# /fuel/packages/orm/
# /fuel/packages/parser/
# dynamically generated files
/fuel/app/logs/*/*/*
/fuel/app/cache/*/*
/fuel/app/config/crypt.php
使用Windows的童鞋注意了,如果你在资源管理器里新建一个.gitignore文件,它会非常弱智地提示你必须输入文件名,
但是在文本编辑器里“保存”或者“另存为”就可以把文件保存为.gitignore了。
有些时候,你想添加一个文件到Git,但发现添加不了,原因是这个文件被.gitignore忽略了:
如果你确实想添加该文件,可以用-f强制添加到Git:
$ git add -f App.class
或者你发现,可能是.gitignore写得有问题,需要找出来到底哪个规则写错了,可以用git check-ignore命令检查:
$ git check-ignore -v App.class
.gitignore:3:*.class App.class
2.配置别名
命令格式
$ git config --global alias.<别名> <原来的git命令>
--global参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有用。
配置Git的时候,加上--global是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用。
配置文件放哪了?每个仓库的Git配置文件都放在.git/config文件中:
例子:
$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch
$ git config --global alias.unstage 'reset HEAD' ——>$ git unstage test.py
显示最后一次提交信息
$ git config --global alias.last 'log -1' ————>git last
显示当前分支提交版本图
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"