目录
这里主要记录以下GitHub的基本用法,其他一些高级的用法有机会再做补充,未必完全正确,欢迎纠正
1. 前提
避免误导,有几个前提说明一下:
- 本地已经安装了git(我是之前已经在Mac上安装了git,所以可以直接使用该命令,按照Git网上应该有很多资料)
- 按照GitHub官网的指导,创建了一个hello-world项目:https://guides.github.com/activities/hello-world/
- 了解GitHub的基本概念:repositories, branches, commits, and Pull Requests. 以及本地项目、远程主机,暂存区等
如果本地已经有项目想要上传GitHub,可以按如下操作:
先在GitHub上面创建一个远程仓库,具体的操作参考GitHub网站说明,创建之后可以看到GitHub给我们提供了几种创建新的远程仓库的指导。我们按照第一种操作,将其中的命令稍加修改即可:
cd /project
echo "# walle" >> README.md
git init
git add .
git commit -m "first commit"
git remote add origin https://github.com/pengyongjun/walle.git
git push -u origin master
2. 克隆项目
我的项目地址是:https://github.com/pengyongjun/hello-world.git
现在我想把项目克隆到本地,以便于本地编辑
克隆的步骤:
- 在本地新建一个存放项目的目录(如temp)
- 进入上一步新建的目录
- 执行clone命令:
$ git clone https://github.com/pengyongjun/hello-world.git
完成以上步骤之后,可以看到temp目录下新增了一个hello-world目录
之后的git命令就要在hello-world目录下执行了
3. 查看分支
3.1 查看本地分支
查看本地分支的命令是:
git branch
说明:前面带*星号的分支名称即本地当前所指向的分支
3.2 查看远程分支
查看远程分支的命令是:
git branch -r
3.3 查看所有分支
查看所有分支的命令是:
git branch -a
4. 本地新建分支
4.1 新建分支
本地新建分支的命令(新建分支:experimental):
$ git branch experimental
4.2 查看新建的分支
使用上一届的 git branch 命令,可以看到新建的分支——experimental
4.3 切换到新分支
切换到新分支的命令:
$ git checkout experimental
其中 experimental 是需要切换到的分支名,命令执行后会提示切换到新分支
4.4 创建+切换新分支
创建分支和切换到新创建的分支可以一步完成,命令如下:
git checkout -b [branch name]
4.5 删除本地分支
git branch -d [branch name]
4.6 clone远程分支到本地
在进行克隆之前,执行一下 git pull 命令
方法一:
git checkout -b 本地分支名x origin/远程分支名x
方法二:
git fetch origin 远程分支名x:本地分支名x
5. 修改并提交分支
5.1 修改分支文件
在分支experimental中做了一些修改之后,这些修改只是保存在了 暂存区
需要将修改进行提交(commit)才能将变更更新到 分支上
commit命令的用法:
git commit -a
执行以上命令,回车之后需要输入一些描述信息(基于vim命令编写即可),描述编辑完成后保存并退出
5.2 新增分支文件
如果是新增了文件,那么不能直接commit,需要先执行:git add命令
例如,在本地master分支新建了一个newFile.txt,那么需要执行以下命令:
$ git add newFile.txt
$ git commit
6. 合并分支到主干
6.1 合并分支到主干
经过上一步修改分支experimental,如果再切换到master(git checkout master),可以看到master中的对应内容并没有修改
此时如果想要将分支experimental中的修改同步到master,就需要进行合并分支操作
将experimental分支合并到master的命令:
$ git merge experimental
6.2 查看合并冲突
上一节是只在experimental中做了修改,所以合并没有任何问题
但是如果在experimental和master中对同一个文件都做了修改,那么合并时就会产生冲突
假如:
- 既在experimental中修改了README.md文件,也在master中修改了该文件
- experimental和master中的修改都已经commit完成
- 当前指向master分支
那么再次执行合并分支命令时,就会提示如下报错:
执行 git status 命令,Git 会告诉你存在一个 “未合并的路径(unmerged paths)”
这只是用另外一个方式告诉你,存在一个或多个冲突:
执行以下命令可以查看具体的冲突详情:
git diff
6.3 解决合并冲突
既然冲突已经存在,那么就需要解决冲突之后才能成功合并;如果有多个文件存在冲突,那就需要一个一个解决
当然,有很多工具可以解决迅速解决合并冲突,需要的自行搜索好了
而且IDEA中也可以快速解决冲突,所以不必担心,我主要是学习这个过程
我当前冲突的文件是README.md,vim命令打开文件,可以看到已经存在关于冲突的说明
现在要做的就是按照实际需要来编辑这个文件(增删改来自两个分支的内容,直到变想要的样子),然后保存
编辑好所有的冲突文件,再次执行命令:$ git commit -a
这次的commit也就是提交合并的结果
至此,有冲突的合并也就完成了
7. 分支同步主干
已有分支有一段时间没有更新过,再次编辑之前,可能需要先将其内容同步为主干最新的内容,操作如下:
- checkout 到 master
- git pull (git pull fetches from origin by default and merges into the current branch.) 获取最新master
- checkout 到 分支
- merge master & 解决合并冲突
8. 本地分支同步远程主机
8.1 修改远程分支
本地分支修改后同步到远程主机的命令格式为:
$ git push <远程主机名> <本地分支名>:<远程分支名>
例如,要将本地的master分支同步远程主机,操作如下:
git push origin master:master
8.2 新增远程分支
同样的,experimental分支只在本地存在,通过下面的方式同步到远程主机之后,远程主机会新建该分支:
8.3 删除远程分支
删除远程分支同样使用push命令,只是将本地分支名称留空
即用一个空白的分支同步远程主机,这样就实现了删除远程分支的目的
9 查看变更历史
9.1 查看所有变更历史
git log
9.2 查看变更历史详情
git show <commit id>
命令行里面的commit id即是git log查询出来的commit值
9.3 查看最新n条变更
git log <-n>
10. 撤销修改
10.1 commit之前的撤销
如果修改了某文件,但是没有commit,现在期望还原到修改之前,则可以用git checkout实现:
10.2 恢复删除的文件
假设我们从本地存储库中删除一个文件,我们想要恢复这个文件。那么可以通过使用git checkout
命令来实现
如下操作即是删除文件之后恢复的操作:
10.3 git reset:更强大的回退
在介绍git reset的用法之前,需要先说明比较重要的一点:
在分支中,有一个HEAD指针指向我们所做的commit, merge 、push 等操作都是针对 HEAD 指针所指向的这个 commit
简单的示例图如下:
而 git reset 命令可以让我们修改 HEAD 指针所指向的 commit,这样就可以达到一个 修改、撤销修改的目的:
通过 git log -[number] 命令结合起来理解上面的内容:
git reset 有三个选项(--soft, --mix 和 --hard,分别适用于三种不同的具体场景):
- git reset --soft <commit id>
- git reset --mix <commit id>
- git reset --hard <commit id>
下面针对这三个选项分别做一个说明:
【git reset --soft <commit id>】
顾名思义,soft是柔软、柔和的意思,git reset --soft <commit id> 即只修改 HEAD 指针
而不会对已 commit 的操作执行回滚,也不会清除暂存区所做的修改
举个具体的例子:
- 对newFile.txt做了第一次修改,并做了commit,记为 commit 1
- 对newFile.txt做了第二次修改,并做了commit,记为 commit 2
- 对newFile.txt做了第三次修改,未提交,这时暂存区记录了这次变更, git status 命令可以查看到未提交的修改
- 这时,HEAD 指针指向 commit 2
- 执行 git reset --soft <commit 1> 命令
- 这时,HEAD 指针指向 commit 1
- 而且 commit 2 所做的变更依然是 commit 的
- 不仅如此,第三次所做的修改也依然记录在暂存区!
.git/logs/HEAD
【git reset --mix <commit id>】
--mix 是 git reset 的默认选项
它与 --soft 的不同之处在于,--mix 会从缓存区回退 commit,即 commit 的内容会回退到 暂存区
还是以上面的例子进行说明:
- 对newFile.txt做了第一次修改,并做了commit,记为 commit 1
- 对newFile.txt做了第二次修改,并做了commit,记为 commit 2
- 对newFile.txt做了第三次修改,未提交,这时暂存区记录了这次变更, git status 命令可以查看到未提交的修改
- 这时,HEAD 指针指向 commit 2
- 执行 git reset --mix <commit 1> 命令
- 这时,HEAD 指针指向 commit 1
- commit 2 所做的变更是非 commit 的,但是已经被记录在 暂存区
- 同样,第三次所做的修改也依然记录在暂存区!
由于修改被记录在暂存区,所以如果用 vim 命令来查看文件的修改,会发现它和 --soft 的结果一样
因为第二次和第三次所做的修改都在 暂存区中
但是如果这时使用 git chechout newFile.txt 将暂存区的内容 撤销, 再 vim 查看 newFile.txt,就会发现只有第一的修改保留下来
第二次和第三次的修改都不复存在了
【git reset --hard <commit id>】
--hard 选项是破坏力最大的,它既回退已经 commit 的内容,也会清除暂存区的内容
所以应该慎用 --hard选项,除非你十分明确你想要做的变更
依然是上面的例子:
- 对newFile.txt做了第一次修改,并做了commit,记为 commit 1
- 对newFile.txt做了第二次修改,并做了commit,记为 commit 2
- 对newFile.txt做了第三次修改,未提交,这时暂存区记录了这次变更, git status 命令可以查看到未提交的修改
- 这时,HEAD 指针指向 commit 2
- 执行 git reset --hard <commit 1> 命令
- 这时,HEAD 指针指向 commit 1
- 这时,变更完全回退到 commit 1 时候的样子,暂存区也是空的
关于 git reset 三个选项更深入的理解,可以参考: