该文档中的git status中的提示语和新版本的不一样,新版本中不再是git reset相关的命令,而是换成了git restore相关的命令
许多网上的资料对同一个问题会有多个解决方案,因为git的命令也在不断的更新
SVN是集中式版本控制的代表,git是分布式版本控制的代表。
git中全是Linux命令
为什么需要版本控制?
个人开发需要不断的改进和迭代,团队内部需要协作,这样的需求就由版本控制工具来满足。
git相对于SVN有一个特点:团队外的人也能贡献代码,git能对团队外的人有一个审核的权限
集中式的版本控制工具有一个缺点:单点故障(如果管理仓库的那台电脑故障了,那所有的历史数据就都丢失了,本地的电脑是不会保存历史版本的信息的)
相对于分布式的版本控制工具:每一个本地电脑都有完整的历史记录,在本地就可以进行版本控制,很好的避免了单点故障
分布式版本控制工具相对于集中式版本控制工具一个非常突出的优点就是可以避免单点故障。
git的优势
- 大部分及操作在本地完成,不需要联网(git是分布式版本控制,在本地是有本地库的,在本地就可以完成版本控制,这一点集中式版本控制就完全做不到,比如SVN,要是断网了跟服务器连不到,你根本进行不了任何的版本控制操作)
- 完整性保证(他会对每次提交的数据进行hash的操作,只要hash只是不变的,那就能保证数据时不变的,比如从git版本库中取出一个文件,那么你就可以拿hash对这个文件进行验证,你对这个文件做的hash和版本库中的hash进行对比,只要是一致的,那就说明这个文件没问题)
- 尽可能添加数据,而不是删除或修改数据(因为如果版本库中的数据有删除或者是修改了,那你就找不回来了。那“尽可能的天添加数据”,就可以避免不可逆的操作,每一次的提交都是一个新的记录)
- 分支操作非常流畅(跟git管理文件的方式有很大的关系,他内部其实是以快照的方式进行管理的,分支其实是对不同快照的不同指针而已,我们创建或切换分支其实很大程度上就是创建和切换指针而已)
- 与linux命令全面兼容(Linux是对任何一个程序员必备的技能,在git bash here打开的git命令行窗口中就可以使用Linux命令)
git 和 代码及托管中心的关系
代码托管中心的任务:维护远程库
有多中代码托管中心:
- 在局域网环境下
- gitlab服务器
- 外网环境下
- GitHub
- 码云
git 命令操作
本地库初始化
1.在已有的文件夹repository1下
git init
2.直接在某个文件夹(例如test文件夹)下
git init repository2
就会在test下建一个repository2的文件夹,内面会有.git 隐藏文件夹
效果:在执行这个命令的文件夹内会会出现一个.git隐藏文件夹,.git文件中存放的是本地库相关的子目录和文件,不要随意改动。
设置签名
作用:区分不同开发人员的身份
注意:设置的签名和登录远程代码中心的账号和密码没有任何关系,你可以设置任意的user.name 和user.email(胡乱设置的email也可以)
有两种:
- 项目级别(仓库级别)
- 系统用户级别
项目级别(仓库级别)
仅在当前本地仓库范围内生效
git config user.name tom_pro
git config user.email tome_pro@qq.com
信息保存位置:./.git/config 文件
系统用户级别
登录当前操作系统的用户范围内
git config --global user.name tom_glb
git config --global user.email tom_glb@qq.com
信息保存位置:~/.gitconfig文件
注:~代表C盘用户文件夹
级别优先级
- 就近原则:项目级别优先于系统级别,二者都有时采用项目级别的签名
- 如果只有系统用户级别的,就已系统用户级别的签名为准
- 二者都没有时,不允许提交
基本操作
状态查看
git status
添加
//提交指定文件
git add [file1 name]…… [filen name]
//提交当前文件夹内的所有文件
git add .
提交
git commit -m "commit msg" [file name]
pro.txt被commit过,然后修改Pro.txt(添加了一行bbb)后git status就会有上图。
如果使用上图提示的git restore pro.txt后,就会发现工作区的pro.txt文件新增的bbb那一行没有了(需要重新打开那个文件)(restore是恢复的意思),所以该命令是恢复工作区的内容到没有修改之前
git commit -a -m "提交的描述信息"
(-a 和 -m的顺序不可颠倒)
git commit 命令的-a 选项可只将所有被修改或者已删除的且已经被git管理的文档提交倒仓库中。如果只是修改或者删除了已被Git 管理的文档,是没必要使用git add 命令的。
同时因为是直接添加到本地库并没有添加到暂存区,所以是不可以撤销的,暂存区存在也是有意义的,意义就是,如果你修改添加到暂存区,如果后悔的话还可以撤回来。
git add .命令除了能够判断出当前目录(包括其子目录)所有被修改或者已删除的文档,还能判断用户所添加的新文档,并将其信息追加到索引中。
查看历史记录
//查看详细提交信息(有时一屏放不下:空格向下翻页,b向上翻页,q退出)
git log
//一行显示
//如果HEAD指针往后退了,那就只能看到HEAD指针之后的版本记录,
git log --pretty=oneline
//一行显示
//如果HEAD指针往后退了,那就只能看到HEAD指针之后的版本记录,
git log --oneline
//可以看到所有提交的历史记录
//查看记录在本地的HEAD和分支引用在过去指向的位置
git reflog
HEAD@{移动到当前版本需要多少步}
前进后退(git reset)
本质:head 指针在不同版本之前切换
- 基于索引值操作 [推荐]
- git reset --hard [局部索引值]
- 知道索引值就可以自由的在所有版本之间进行任意切
- 使用^符号:只能后退
- git reset --hard HEAD^
- 注:一个^表示后退一步,n个表示后退n步
- 只有~符号:只能后退
- git reset --hard HEAD~n
- 注:表示后退n步
- 使用^或~或[局部索引值]执行后退操作后,还可以git reset --hard [局部索引值]进行前进(因为他可以在任意版本之前切换)
- 使用git reset --hard HEAD就是切换到当前指针指向的位置
reset 命令的三个参数对比
- --soft
仅在本地库移动HEAD指针(例如,你正在工作区修改内容,在文件尾部加了一行3,你再使用--soft倒退版本,这个时候工作区的内容是没有任何影响的,文件尾部还是有3的,疑问:现在暂存区有内容吗?如果有,是什么)
- --mixed
在本地库移动HEAD指针,重置暂存区
- --hard
在本地库移动HEAD指针,重置暂存区,重置工作区
- 不设置默认是mixed
撤销操作
- 从暂存区撤销回工作区
(把文件添加到暂存区后查看git status时,会有这条命令的提示)
git reset HEAD [filename]
- 撤销对文件的修改
如果你并不想保留对 CONTRIBUTING.md 文件的修改怎么办? 你该如何方便地撤消修改——将它还原成上次提交时的样子(或者刚克隆完的样子,或者刚把它放入工作目录时的样子)? 幸运的是,git status 也告诉了你应该如何做。 在最后一个例子中,未暂存区域是这样:
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: CONTRIBUTING.md
它非常清楚地告诉了你如何撤消之前所做的修改。 让我们来按照提示执行:
$ git checkout -- CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: README.md -> README
可能新版本的git做出了改变(提示语变的和参考手册不一样了,但是按照参考手册的操作,工作区的文件确实回到了上一次提交的时候):
请务必记得 git checkout -- <file> 是一个危险的命令。 你对那个文件在本地的任何修改都会消失——Git 会用最近提交的版本覆盖掉它。 除非你确实清楚不想要对那个文件的本地修改了,否则请不要使用这个命令。
现在,假设你不但改错了东西,还从暂存区提交到了版本库,怎么办呢?还记得版本回退一节吗?可以使用git reset回退到上一个版本。不过,这是有条件的,就是你还没有把自己的本地版本库推送到远程。还记得Git是分布式版本控制系统吗?我们后面会讲到远程版本库,一旦你把stupid boss
提交推送到远程版本库,你就真的惨了……
小结
又到了小结时间。
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file
。
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD <file>
,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。
git重置某些文件到指定版本
对这个博客中的一些解释:
Git 中 git checkout -- <file>的真正用法:该指先是从缓存区中拉取版本还原,如果没有再到版本库中拉取还原。
--的意思是:
Do not interpret any more arguments as options.=》
不要将其他参数解释为选项。
刚刚做了一些提交,但是你发现刚做的提交不完整或者有错误,想要重新编辑后再提交
git reset --soft HEAD^
先让本地库回到上一个版本,然后在工作区重新编辑后
git commit -a -c ORIG_HEAD
-a 参数设置修改文件后不需要执行 git add 命令,直接来提交
-C(大写)重用日志消息和作者信息(包括时间戳)
-c(小写) 重用日志消息和作者信息(包括时间戳),会调用编辑器,以便用户可以进一步编辑提交消息。
针对某些危险操作,Git通过记录HEAD指针的上次所在的位置ORIG_HEAD提供了回退的功能。当你发现某些操作失误了,比如错误的reset到了一个很早很早的版本,可以使用git reset --hard ORIG_HEAD回退到上一次reset之前。(就是上一次HEAD指针指向的地方)参考文章
也可以使用git commit --amend,具体使用方法:
适用场景(参考文章链接):
场景1.本地开发代码已提交,提交后发现这次提交的代码有问题,或者漏提交了一些文件,此时,希望达到以下目的:
①修改有问题的代码。
②补足漏提交的文件(一般是新增的文件没有git add .)
③把以上2点相关的代码,和前一次提交的代码合并成1个提交。
④给合并后的这个提交添加新的注释。
解决办法:
--》修改问题代码
--》git add . (把漏提交的文件假如暂存区)
--》执行git commit --amend -m "这里填写提交的注释"
场景2.新接到需求,需要基于master分支拉取一个feature分支,且这个feature分支只有你自己使用(这一点极其重要),由于开发周期较长,你不想每一次都产生一个新的commit,而是每一次commit都修改前一次提交,这样做的好处是,等到你的feature分支提测时,就只有1个干净的commit,没有乱七八糟的提交历史,你只要把这1个commit合并到master里就好了 。
解决办法:在feature分支上,
第1次提交代码时,使用git commit -am "第1次提交的注释"
第2次以后提交代码时,使用git commit --amend -m "这里填写提交的注释"
这样,整个分支可以只有1个commit
删除文件并找回
前提:删除前,文件存在时的状态提交到了本地库
操作:git reset --hard [指针位置]
本质就是,回到该文件还没有被删除的记录上
删除操作已经提交到本地库:指针位置指向历史记录
删除操作尚未提交到本地库:指针位置使用HEAD
注: git reset HEAD可以将添加到暂存区的文件取消暂存
已提交到本地库的文件,在工作区删除后,添加到暂存区,这时候如何撤回
还是 git reset --hard HEAD
因为 --hard就是代表在本地库移动HEAD指针,重置暂存区,重置工作区
比较文件差异
- git diff [文件名]
将工作区的文件和暂存区的进行比较
git diff [本地库中历史版本] [文件名]
例如:git diff HEAD -- readme.txt
将工作区的文件和本地库历史记录进行比较git diff
不带文件名:比较多个文件
注:git branch 是查看本地的所有分支 git branch -a 是查看本地分支和远程分支
创建分支
git branch [分支名]
查看分支
git branch -v
切换分支
git checkout [分支名]
合并分支
- 第一步:切换到接受修改的分支(被合并,增加新内容)上:git checkout [被合并分支]
- 第二步:git merge [有新内容分支名]
例如在master分支合并dev分支:
git merge --no-ff -m "merge with no-ff" dev
--no-ff代表生成一个新的提交节点
参考
解决冲突
- 本地分支操作冲突
例如master分支和dev分支都修改了demo.txt文件,在master分支上将dev分支的内容merge过来时,就会有冲突,这时只要在master分支上将冲突文件修改到满意程度,保存退出。然后正常add和commit就可以了。
- 多人协作操作冲突
远程分支上的demo.txt已经有新的内容了,但是本地没有拉取下来,直接在本地的demo.txt上修改了,然后推送到本地仓库,这时是没有冲突的,但是将本地仓库push到远程时就会提示冲突。这时现将远程pull下来,然后就可以看到冲突的文件,进行修改后推送到远程就可以了。
- 第一步:编辑文件,删除特殊符号
- 第二步:把文件修改到满意程度,保存退出
- 第三步:git add [文件名]
- 第四步:git commit -m "日志信息"
- 注意此时commit 一定不能带具体文件名
和远程之间的交互
例如你是先建立了一个本地库,在内面做了一些提交,现在要把它推送到远程库:
- git init
- 设置user.nane 和user.email(如果曾经设置过全局的,就可以跳过这一步)
- edit文件
- git add 。
- git commit -m "msg"
- 现在要办本地库的信息推送到远程库,其实本地库和远程库的名字可以不同。先在远程库中建立一个仓库,注意不要添加readme文件,避免和本地库冲突,创建好后就可以进行推送了
-
先给远程库设置别名,因为你之后的推送要告诉本地库推送到哪个地址
20201126193339 - git remote -v查看远程库列表
-
20201126193557
fetch表示这个地址用来取回,push代表这个地址用来推送
- git push origin master代表将master分支推到远程(origin是上一步设置的远程仓库的别名),之后会弹出github登录框(但是我操作的时候并没有,因为我之前已经登录过github,他会自动将账号和密码保存在Windows凭据中,如下图,删掉后就要重新登录)(如果是别人clone下来想要提交,那必须远程仓库的owner将他添加为开发人员)
- 别人拉取这个远程库就可以git clone https://github.com/diamondooo/demo2.git,这个clone命令有以下做用:一、创建origin远程地址别名(git remote -v可以看到origin带表的地址)。二、完整的把远程库下载到本地(git branch -v可以看到除了本地的master分支外还可以看到origin/master这个远程分支)。三、初始化本地库。
- git fetch origin master把远程库的最新操作拉取下来,但只是拉取到本地库(拉取到本地库的origin/master),工作区的内容不会变化,因为你现在在本地的master分支上,不是在本地的origin/master分支上,所以看不到远程库的内容
- 在fetch之后,想要看远程库到底做了哪些修改,就可以使用 git checkout origin/master 检出origin的mater,就可以在工作区看到最新的文件,但这只是查看。git checkout master回到本地的master还是旧的内容,git merge origin/master将远程的master合并到本地的master(执行这个操作时是在本地的master分支上),这样本地的master分支就有最新的内容了。git pull其实是git fetch加上git merge的效果。
pull=fetch + merge
git fetch [远程库地址别名] [远程分支名]
git merge [远程库地址别名/远程分支名]
git pull [远程库地址别名] [远程分支名]
SSH免密登录
因为windows自带的票据管理,第一次登录过GitHub后就会将账号和密码保存到本地,之后的推送就不用登录了,如果系统不带这个功能,那么每次推送都需要登录,很麻烦,这时就用SSH免密登录
输入 ssh-keygen -t rsa -C 登录GitHub的邮箱,然后一路回车,就可以了。这个命令要在C盘登录这个电脑的账号下输入(和全局的user.name 和 user.email 同一个目录)。这时就会有.ssh隐藏文件夹。
复制 id_rsa.pub文件的所有内容,粘贴到自己的GitHub的SSH and GPG keys内
如果想用ssh登录,就要做如上操作,往ssh路径上推。
标签
git push 的 -u 参数具体适合含义?
比如远程库A上有3个分支branch1、branch2、branch3。远程库B上有3个分支branchx、branchy、branchz。本地仓库有2个分支local1和local2。那么当初始状态时,local1和local2和任何一个分支都没有关联,也就是没有upstream。当通过git branch --set-upstream-to A/branch1 local1命令执行后,会给local1和branch1两个分支建立关联,也就是说local1的upstream指向的是branch1。这样的好处就是在local1分支上执行git push(git pull同理)操作时不用附加其它参数,Git就会自动将local1分支上的内容push到branch1上去。同样,local2分支也可以和远程库A和远程库B上的任何一个分支建立关联,只要给local2分支设置了upstream,就可以在local2分支上用git push(git pull同理)方便地与目标分支推拉数据。
综上所述,upstream与有几个远程库没有关系,它是分支与分支之间的流通道。
再来说说git push -u和git branch --set-upstream-to指令之间的区别。
举个例子:我要把本地分支mybranch1与远程仓库origin里的分支mybranch1建立关联。
(如果使用下列途径1的话,首先,你要切换到mybranch1分支上(git checkout mybranch1))
两个途径:1. git push -u origin mybranch1 2. git branch --set-upstream-to=origin/mybranch1 mybranch1
这两种方式都可以达到目的。但是1方法更通用,因为你的远程库有可能并没有mybranch1分支,这种情况下你用2方法就不可行,连目标分支都不存在,怎么进行关联呢?所以可以总结一下:git push -u origin mybranch1 相当于 git push origin mybranch1 + git branch --set-upstream-to=origin/mybranch1 mybranch1
简单来说使用git push -u origin master以后就可以直接使用不带别的参数的git pull从之前push到的分支来pull。
作者:王轩
链接:https://www.zhihu.com/question/20019419/answer/48434769
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
git push origin
上面命令表示,将当前分支推送到origin主机的对应分支。
如果当前分支只有一个追踪分支,那么主机名都可以省略。
git push
如果当前分支与多个主机存在追踪关系,那么这个时候-u选项会指定一个默认主机,这样后面就可以不加任何参数使用git push。
git push -u origin master
上面命令将本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了。
不带任何参数的git push,默认只推送当前分支,这叫做simple方式。此外,还有一种matching方式,会推送所有有对应的远程分支的本地分支.Git 2.0版本之前,默认采用matching方法,现在改为默认采用simple方式。
git rebase
翻译为"变基"
通过git rebase -i 将本地的多次提交合并为一个,以简化提交历史。本地有多个提交时,如果不进行这一步,在git rebase master时会多次解决冲突(最坏情况下,每一个提交都会相应解决一个冲突)
git 操作的疑问:
1.本地检出一个新分支后,如何推送到远程
2.添加到暂存区的文件,如何撤回到工作区
3.提交到本地库的文件,如何撤回到暂存区/工作区,这两种有何区别
4.git reset 和git revert 有和区别
5.远程的新分支如何拉取到本地
6.git reset 的hard 和soft 和mixed有何区别
7.查看提交记录有几种方式,有git log 、git reflog ……
8.git diff有几种方式
9.git 的简写有哪些,比如 git st 代表git status 等等
10.git checkout hash 检出这个版本后,就可以直接在这个版本上修改了吗,修改之后的提交会覆盖这个版本之后的版本吗?这种也算是一种吃后悔药的方式吗?
11.加上ssh文件夹和直接使用git账号登录有什么区别?
12.常用命令有哪些(尽可能列出所有)
13.git的撤销操作:从暂存区撤回到工作区(未提交过的文件和已提交过的文件有区别),从仓库撤回到暂存区,从仓库撤回到工作区
14.git reset --hard [版本号] 和git checkout 版本号有什么区别