GIT 笔记
1.安装
截至到我编辑的时间,git最新版本是Git-2.18.0 for 64 windows,可惜官网git-scm.com下载速度极慢,我就在太平洋网站下载了64 bit for windows的版本呢,安装包大概37M 左右。安装windows还是相当简单,一直点击next就搞定。安装完成后需要设置
git config --global user.name "Your Name"
git config --global user.email "email@example.com
否则会报错的。
2.创建库
我自己在本地创建了一个目录XXXrepository,完了右键鼠标,Git Bash Here 弹出命令框。完了,在命令行中
git init
即创建了.git的初始化版本库。
3. 概念
工作区和暂存区
git status 查看状态
工作区:我们被管理,要操作的目录系统都属于工作区。
暂存区:stage。
我们把文件添加的库里面,需要两步:
1.通过git add 把文件添加到暂存区。
2.通过git commit 把暂存区的文件提交到当前分支里面。
管理修改
第一次修改 -> git add -> 第二次修改 -> git commit,我们发现只能提交第一次的修改。
Git管理的是修改,当你用git add命令后,在工作区的第一次修改被放入暂存区,准备提交,但是,在工作区的第二次修改并没有放入暂存区,所以,
git commit只负责把暂存区的修改提交了,也就是第一次的修改被提交了,第二次的修改不会被提交。
第一次修改 -> git add -> 第二次修改 -> git add -> git commit,这样才把第二次修改的提交。
4. 版本回退
git log 可以查看最近的 历史纪录
git log --pretty=oneline 同上,只是简略信息很长的用SHA1计算出来的十六机制ID,是标识版本好的commit id
git中HEAD 表示当前版本
HEAD^ 当前的上一个版本
HEAD^^ 当前的上上一个版本
git reset --hard HEAD^ 表示回退到上一个版本
git reset --hard [commit id] 版本号可以不用写全,前几位就可以了,git 会自动去找,当然也不能只写前一两位,因为git可能找到多个版本,就无法确定是哪一个了。
git reflog 查看每一次的命令。
5. 删除文件
git rm file ,删除文件,然后提交
git checkout -- file 撤销删除,和上面撤销修改一样,git checkout 其实是用版本库的版本替换工作区的版本,无论工作区的版本是删除或者更改,都可以还原。
6. 远程仓库
由于你的本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以需要创建密钥。
ssh-keygen -t rsa -C "email@163.com" //创建SSH KEY
==>next
Enter file in which to save the key (/c/Users/name/.ssh/id_rsa): ssh_key.txt 更改为id_rsa
Enter passphrase (empty for no passphrase):password
Enter same passphrase again:password
这样就创建成功,注意你查看pwd得目录,这两个文件是保存在你当前操作目录下的。
第一个输入的ssh_key.txt是私钥,第二个.pub是公钥,是可以放心告诉别人的。
==>next
登陆GitHub,打开Account settings,点击Add SSH KEY,填上任意Title,在key文本框里粘贴ssh_key.txt.pub文件的内容
==>next
本地库lsjRepository和github我创建的lsjRepository相关联
git remote add branch1 git@github.com:name/XXXRepository.git
==>next
把本地库的分支 test_branch1推到github里面去
git push -u branch1 test_branch1
但是此时报错:确认有权利或者有库存在。
ssh -T git@github.com
测试权限,报错:git@github.com: Permission denied (publickey).
解决方式虽然很曲折,但最终成功了。
注意:错误1:输入密码必须是你的github账号的密码,我上面输入的password不是正确密码。
错误2:ssh_key.txt这是我自定义生成私钥的文本文件,不得行,必须明为:id_rsa 无后缀
错误3:我生成密钥是成产在操作目录下的,必须拷贝到${用户}$/.ssh目录下。
错误4:github复制的是公钥,不是私钥。
最后用命令 git push -u branch1 test_branch1
需要输入你的登陆密码,终于成功了。
解析一下,branch1是上面用git remote add 的远程库名,test_branch1是本地的当前分支
git pull 错误 : Connection reset by 13.250.177.223 port 22
同时ping github.com连接超时的话,在hosts文件配置:
192.30.255.112 github.com git
185.31.16.184 github.global.ssl.fastly.net
7. 分支管理
查看分支:git branch -a
创建分支:git branch <name>
切换分支:git checkout <name>
创建+切换分支:git checkout -b <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>
删除远程分支:git push origin --delete <name> (说明:name 不能包含remote/xx/xx了,直接分支名就OK)
删除本地分支:git branch -D <name> ,这个属于强制删除,但是假如你在当前分支使用这个命令想删除自己分支,是不行的。你需要切换到其他分支来删除当前分支。
删除远程分支如果遇到这样的错误:error: unable to delete 'remotes/origin/V2.0': remote ref does not exist
解决方案是首先清除远程分支的本地缓存:git fetch -p origin
关联本地分支和上游分支:git branch --set-upstream-to=origin/V2.5-test V2.5-test
创建远程分支: 先git checkout -b <name>创建本地分支,这里非常重要的一点是,在哪个当前分支创建的,就表明新分支从哪里来的。第二步是:
git push origin <本地src分支> : <远程dst分支>,由下面8的概念逻辑可以用:git push origin <本地src分支>
从一次提交拉一个分支: git checkout -b branchname <commitId>
8. 概念逻辑
origin:dev
这是库origin下的dev分支。
git push origin master
这里重点强调:origin 这个表示你要提交到远程的哪个库,origin其实就是一个库的标签,比如我本地clone的我自己的库,
我用git remote -v 查看我自己库关联的远程库是哪个:
a
b
master 是哪个远程库下面的哪个分支。 master 其实是一个refspec ,正常的refspec 是<src>:<dst>,冒号前是local branch 的名字,
冒号后面是remote branch的名字,如果省略了dst,git 就认为你想push到remote repository下和local branch相同名字的branch,上面那句就等价于
git push origin master:master
9. github拷贝
上面第6点是从本地和github建立关联,而我这里要说的是再github建立库,然后从github克隆下来。两个不一样的,前者需输入密码,后者需要输我的github的用户名和密码。
10.upstream 和 downstream
意思是本地库A的分支dev push到远程库B的分支devRemote,此时B的devRemote就是A的upsream,而A的dev就是B的devRemote的downstream,他们是相对的。
11.reset
当我reset 的时候懵逼了,eclipse会让我选择reset type(Soft[HEAD updated],Mixed[HEAD and index updated],Hard[HEAD,index and working tree updated]).
- 类型一:软,只重置HEAD
- 类型二:混合,重置HEAD 和 index
- 类型三: 硬,重置 HEAD 、index 和working tree
- 类型四: 保留,即保留本地更改,直接回退到某个版本。
现在需要解释一下这三个概念了:
- HEAD:这是我当前分支最顶端的别名,也就是指向我最近一次提交的。
- Index: 这个被称为staging area, 它对应的是eclipse的Staged Changes ,也就是即将要提交的一个文件集。也就是git add 进来的缓存区,我通过
bash here 用git add .然后到eclipse 里右侧的Git Staging 点击刷新按钮,就可以看到git add . 操作生效,文件由Unstaged Changes 跑到
Staged Changes里面去了。
- working tree:这个就是我的工作空间,说白了就是本地文件集合,比如我更改后按ctrl+s ,这时eclipse 的Unstaged Changes 就有文件列表。所以,
如果把working tree 重置的话,就相当于把你本地的更改也重置了。
所以这里就用eclipse 对应一下:
working tree 改变的文件集 <====> eclipse 放在 Unstaged Changes
Index 的文件集 <====> eclipse 放在 Staged Changes
对应的命令:
1:git reset –-mixed:此为默认方式,不带任何参数的git reset,即时这种方式,它回退到某个版本,只保留源码,回退commit和index信息
2:git reset –-soft:回退到某个版本,只回退了commit的信息,不会恢复到index file一级。如果还要提交,直接commit即可
3:git reset –-hard:彻底回退到某个版本,本地的源码也会变为上一个版本的内容
--mixed reset HEAD and index
--soft reset only HEAD
--hard reset HEAD, index and working tree
--merge reset HEAD, index and working tree
--keep reset HEAD but keep local changes
12.更改邮箱和用户名
我今天查看git log时,发现我的代码提交用户名是daye,邮箱是name@163.com,是我个人邮箱和我个人昵称,尴尬。这里讲一下更改邮箱和用户 名。
可以直接用命令改:
git config --global user.name daye
git config --global user.email company@company.com
也可以在当前项目下,git bash here ,到 ~/.gitconfig 里面去更改。
13.库提交,前提是已经配置了私钥
- a.本地创建一个maven 工程zhehan
- b.它的目录下 git bash here 然后,git init 生成.git 文件,也就创建了一个本地库,然后git add . 增加,git commit -m 'init' 提交
- c.github也创建一个zhahan.git的库,然后添加一个read.me文件
- d.本地git remote add origin git@github.com:lio/zhehan.git 创建关联,此时会在本地.git的config 文件里增加三行
[remote "origin"]
url = git@github.com:lio/zhehan.git
fetch = +refs/heads/*:refs/remotes/origin/*
- e.提交 git push --set-upstream origin master 这里提交,同时设置github的分支是本地分支的上游,origin 是远程库,master是本地分支,向
远程库推送本地分支,此时报错
fatal: 'git@github.com/lio/zhehan.git' does not appear to be a git repository
fatal: Could not read from remote repository.
Please make sure you have the correct access rights and the repository exists.
解决方式是 git remote set-url origin git@github.com:lio/zhehan.git 然后就可以git pull 但是两个不相干的库拉取需要
git pull origin master --allow-unrelated-histories
push的时候也要设置上游
git push --set-upstream origin master
注意:这里的url git@github.com: .com 后面是【冒号】不是【斜杠】,虽然git remote add可以斜杠和冒号不分,但是git remote set-url是必须冒号的。
14.从github拉取
a.本地创建目录CQGas,然后git bash here ,git init
b. git remote add origin git@github.com:lio/CQGas.git
c.git pull origin master --allow-unrelated-histories
15.git 的日志查看
--pretty=oneline:一行显示,只显示哈希值和提交说明(--online本身也可以作为单独的属性)
--pretty=format:” ":控制显示的记录格式,如:
%H 提交对象(commit)的完整哈希字串
%h 提交对象的简短哈希字串
%T 树对象(tree)的完整哈希字串
%t 树对象的简短哈希字串
%P 父对象(parent)的完整哈希字串
%p 父对象的简短哈希字串
%an 作者(author)的名字
%ae 作者的电子邮件地址
%ad 作者修订日期(可以用 -date= 选项定制格式)
%ar 作者修订日期,按多久以前的方式显示
%cn 提交者(committer)的名字
作者和提交者的区别不知道是啥?
作者与提交者的关系:作者是程序的修改者,提交者是代码提交人(自己的修改不提交是怎么能让别人拉下来再提交的?)
其实作者指的是实际作出修改的人,提交者指的是最后将此工作成果提交到仓库的人。所以,当你为某个项目发布补丁,然后某个核心成员将你的补丁并入项目 时,你就是作者,而那个核心成员就是提交者(soga)
%ce 提交者的电子邮件地址
%cd 提交日期(可以用 -date= 选项定制格式)
%cr 提交日期,按多久以前的方式显示
%s 提交说明
第一种例子:git log --pretty=oneline
第二种例子:git log --pretty=format:"%an %ae %ad %cn %ce %cd %cr %s" --graph
: git log --pretty=format:"%H %cn %cd %s" --graph
16. 合并指定文件或文件夹到当前分支
git checkout 其他分支 文件1 文件2 文件 3;
git status 就可以看见文件1 文件2 和 文件3
也可以合并目录 git checkout 其他分支 目录1; 把目录1下面的文件强制覆盖当前分支的目录1下的文件。
Liao_@LAPTOP-QKF1DI4I MINGW64 /d/company_workspace/sw-charge-starter (V2.5.1-SaaS)
$ git checkout project-jj alipay-keys
比如上面即是把project-jj分支的alipay-keys目录下的文件合并到V2.5.1-SaaS的alipay-keys目录下
同时,也可以用cherry-pick (摘樱桃)的方式合并某个commit 或者某几个commit
单个:git cherry-pick 分支名称 commit_id
多个:git cherry-pick 分支名称 commit_id1 .. commit_id2
17. beyond compare 和git集成
a. 配置如下:
在c/Users/Liao_/.gitconfig里面
[user]
email = name@company.com.cn
name = name
[difftool]
prompt = false
[difftool "bc4"]
cmd = \"D:/Program Files/Beyond Compare 4/BCompare.exe\" \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$MERGED\" \"$MERGED\"
trustExitCode = true
b. 命令用法:
git difftool -t bc4 [文件]
git difftool -t bc4 --dir-diff --no-symlinks 连文件夹也给弄出来
同样,如果要把两个commitid的文件比较都用bc展示出来,牛逼的命令就这样诞生了。
git difftool -t bc4 1625a74c3f0fd7455d06fc869410257a1c321398 HEAD -d --no-symlinks
在比较两个版本时, 合并代码一般都是挨个检查,我习惯是右手边放旧的需要合并的版本,左手边放新的需要合并的版本。
注意:
git difftool 调用beyond compare 只能单向保存,即当前分支如果是右边的话,只有左边copy过来的文件生效,如果想把右边copy到左边是不生效的。
还有,如果左边有新增的文件要合并到右边来的话,无论怎么copy都是不生效的。我的做法是:
1. 把这些所有新增的文件全部选中,ctrl + 左键挨个点选。
2. copy file name
3. 粘贴到notepad++ 中,np++来把这些新增文件列表处理: 多行转成一行,用空格隔开。
4. 先把项目的相对路径前面存放在c盘的path删掉。右斜杠替换成左斜杠(普通方式替换)。
5. 查找模式中更改成正则表达式,把 \r\n 替换成空格,这是把多行转一行的方式。
6. 然后 git checkout (源分支名称) 刚才处理的新增文件列表,git status 就有了。 例如: git checkout dev file1.txt file2.txt file3.txt
18. stash的应用
(1) git stash save "save message" : 执行存储时,添加备注,方便查找,只有git stash 也要可以的,但查找时不方便识别。
(2) git stash list :查看stash了哪些存储。
(3) git stash show :显示做了哪些改动,默认show第一个存储,如果要显示其他存贮,后面加stash@{$num},比如第二个 git stash show stash@{1}
(4) git stash show -p : 显示第一个存储的改动,如果想显示其他存存储,命令:git stash show stash@{$num} -p ,比如第二个:git stash show stash@{1} -p 。
(5) git stash apply :应用某个存储,但不会把存储从存储列表中删除,默认使用第一个存储,即stash@{0},如果要使用其他个,git stash apply stash@{$num} , 比如第二个:git stash apply stash@{1} 。
(6) git stash pop :命令恢复之前缓存的工作目录,将缓存堆栈中的对应stash删除,并将对应修改应用到当前的工作目录下,默认为第一个stash,即stash@{0},如果要应用并删除其他stash,命令:git stash pop stash@{$num} ,比如应用并删除第二个:git stash pop stash@{1}。
(7) git stash drop stash@{$num} :丢弃stash@{$num}存储,从列表中删除这个存储。
(8) git stash clear :删除所有缓存的stash
19. 查看两个版本之间的修改文件列表
git diff --name-only HEAD~ HEAD
20. 标签
列出所有标签: git tag
检索某个标签: git tag -l <标签名> 标签名也可以是模糊匹配,如:git tag -l 5.*
切换到某个标签: git checkout <标签名>
创建轻量标签: git tag <标签名> -light 轻量标签指向一个发行版的分支,其只是一个像某commit的引用,不存储名称时间戳及标签说明等信息
创建带备注的标签: git tag -a <标签名> -m "备注信息"
创建指定CommitID的标签: git tag -a <标签名> <CommitID> -m "备注"
删除指定标签: git tag -d <标签名>
推送所有标签: git push origin --tags
推送指定标签: git push origin <标签名>
删除远程仓库的标签: git push origin --delete <标签名>
21. .git
当git仓库某些文件删除了,但.git的缓存仍占用着很大的磁盘空间,可以用此命令清理:
git filter-branch --tree-filter 'rm -f BIG-FILE' HEAD
22. 每次都要输入git用户名和密码
git config --global credential.helper store