Git_basic
Git 基础
学习笔记,仅供参考
参考:青空の霞光视频讲解-git 部分 | Pro Git 中文版 | Git 官网参考文档
目录:
1. 概念
三种状态
已修改(modified),仅对文件做出修改,还未保存到库中
已暂存(staged),对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中
已提交(commited),文件已被安全地保存在库中
由此引出对应的三个工作区域的概念
工作目录,在本地能够修改、查看文件的目录,即本地的项目文件夹
暂存区(Index),它是 .git 下的一个名为 index 的文件,用来保存下次提交文件的列表信息
Git仓库(本地仓库),以 .git 为名的目录,远程提交和拉取项目的重要目录
工作流程,用户先在本地仓库中创建或修改文件,然后将文件的快照保存到 index 中,接着依据 index 将快照永久性地保存在 git 仓库中。若是想要在网络上能看到文件,可将其保存到远程仓库中。大致工作流程图如下:
2. 基本命令
2.1. 信息配置
通常在安装完 git 后,会先配置下用户信息,这样后面的提交都会带有这些信息
git config --global user.name "Tom"
git config --global user.email "tom@example.com"
# --global 表示仅配置一次,后续直接使用
git config --list # 列出git的所有配置项
2.2. 获取 git 仓库
两种获取 git 仓库的方法,分别是初始化本地目录将其从而创建一个 git 仓库;从网上克隆获取
git init
# 当前目录创建出 .git 目录
git clone https://github.com/xxx/xx
# 从 github 上克隆项目,其中在 xxx 中会初始化出 .git 目录,并将远程的数据存放其中
2.3. 仓库状态
在工作目录下的文件会有两种状态:已跟踪和未跟踪。已跟踪文件是指那些已被纳入 git 管理的文件,它们会随着 git 的操作被加入到本地仓库或远程仓库中。被跟踪的文件在 git 管理中,就会是已修改、已暂存和已提交这三种状态之一。同理,未跟踪的文件就不会受 git 操作的影响,也就是普通的本地磁盘文件。
git status
# 查看当前目录的文件状态
根据上图,git status 会显示那些是已跟踪的,那些是未跟踪的,且 git 会显示出已跟踪文件的状态。同时,给出一些建议来后续操作文件
2.4. 添加
git add test.txt
# 将 test 文件变为已跟踪文件
git add .
# 将当前目录的所有文件都添加到暂存区
git restore --staged test.txt
# 将暂存区的文件变为未跟踪文件
注意,命令行界面会用颜色来区分一些文件的状态,如红色指未跟踪文件或是跟踪已修改文件;绿色指跟踪已暂存文件;若已提交文件就不再显示文件的状态
2.5. 查看已暂存和未暂存的修改
git diff
# 查看暂存区中已修改文件的修改内容
git diff --cached
# 查看暂存区中未修改文件的改动
git diff --staged
# 在 1.6.1 之后新增的,与 --cached 相同
在命令显示的结果中, + 号指文件新增的内容,- 号指删除的内容
2.6. 提交
当修改后的文件添加至暂存区后,就可将暂存区的记录改变提交到 git 仓库中。而且每次提交都会有快照记录,便于以后回滚。
git commit
# 无参数的提交,它会进入 vim 界面,先显示最后 git status 的输出,然后要求输入提交说明
git commit -m 'Initial commit'
# -m 指在命令时就添加提交说明
git commit -a -m 'Initial commit'
# -a 指包含 git add 操作
2.7. 删除和移动文件
git rm <file>
# 当前目录和暂存区都将删除的 file 文件
git rm log/\*.log
# 删除 log 目录下所有以 log 为后缀的文件
git rm -f <file>
# 强制删除暂存区中已修改文件
git rm --cached <file>
# 删除文件,但当前目录仍保留此文件,
# 即将暂存区中已提交的文件变为未跟踪文件
git checkout <file>
# 恢复在当前目录下删除或修改的文件,且该文件处于 unstaged 状态
git reset --hard commitId
# 通过回滚来恢复 git rm 命令删除的文件
git mv <file> <new_file>
# 重命名文件,并在暂存区保存记录
2.8. 查看提交历史
git log
# 列出所有的提交历史,head 指当前所处于的提交,内容包含 commitId、作者、日期和提交说明
git log -p -2
# -p 显示每次提交的内容差异,-2 指显示最近两次的提交
git log --stat
# 对每次的提交作统计
git log --oneline --graph
# 简要输出信息并以图形形式显示
git reflog
# 查看所有的提交历史
2.9. 忽略文件
在 .gitignore 文件下所匹配到的文件不会被加入到 git 的管理当中。以下面的 .gitignore 为例
# 忽略所有以 a 做后缀的文件
*.a
# 不忽略 lib.a 文件
!lib.a
# 仅忽略当前目录下的 TODO 文件
/TODO
# 忽略 build 目录下的所有文件
build/
# 忽略 doc 目录下所有的 txt 文件
doc/*.txt
# 忽略 doc 子目录中的所有 pdf 文件
doc/**/*.pdf
2.10. 打标签
给某次提交打上标签来表示本次提交的文件变化,算是对提交的额外说明
git tag
# 列出所有的标签
git tag -l 'v1.8.5*'
# 列出 v1.8.5.x 的所有版本标签
git tag -a v1.0 -m 'my version 1.0'
# -a 指给当前提交(head所指的)打上标签,v1.0 指该提交的标签名,-m 为标签说明
git tag -a v1.2 -m 'my version 1.2' 9fceb02
# 给指定的提交打标签
git show v1.0
# 根据标签名来显示具体的提交信息
git push origin v1.0
# 默认下,git push 不会将标签传给远程服务器,所以需要手动推送
git push origin --tags
# 一次推送多个标签
3. 分支
3.1. 分支概念
分支本质上就是指向提交对象的可变指针,因为每次提交都会创建一个提交对象,且该对象的父对象是上次提交对象。
git branch testing
# 创建一个新的分支 testing,即仅是新建一个可变指针
# 并且它们都能指向提交历史的任一提交对象
git checkout testing
# 让 head 指向 testing 分支
# 在切换分支时,最好确保工作目录和暂存区的文件都已提交,防止后期操作冲突
git checkout -b testing
# 创建并切换到新分支 testing
git branch -d testing
# 删除 testing 分支
3.2. 合并
当 master 分支想拥有 testing 分支的提交时,就可使用合并来完成
git merge testing
# 在 master 分支下合并 testing 分支的内容
分支也会有两种情况,一种是没分叉的;一种是分叉的
这种一条线的情况,只会简单地让指针右移,并不需要解决分歧问题
这种情况就是常见的分支合并,Git 会自行决定选取哪一个提交作为最优的共同祖先,并以此作为合并的基础
但有时会因为 master 和 iss53 对相同文件做了不同的修改操作,从而导致合并时发生冲突,这时仅会将两个分支的内容合并,并不会提交创建一个新快照。直到手动解决文件冲突,再手动添加至暂存区和提交。
# 比如下面以 master 和 testing 分支分别不同地修改 hot.txt 文件为例
$ git merge testing
Auto-merging hot.txt
CONFLICT (content): Merge conflict in hot.txt
Automatic merge failed; fix conflicts and then commit the result.
# 在 master 下合并 testing 分支而发生冲突
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Changes to be committed:
modified: hello.txt
deleted: test.txt
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: hot.txt
# 查看那些因包含合并冲突而处于未合并(unmerged)状态的文件
$ git diff
diff --cc hot.txt
index 66f2795,2365a9e..0000000
--- a/hot.txt
+++ b/hot.txt
@@@ -1,3 -1,2 +1,7 @@@
It's so hot.
++<<<<<<< HEAD
+Test line
+I want drink a juice.
++=======
+ I need water.
++>>>>>>> testing
# 查看冲突文件在两分支下不同的修改
# ====== 为分割线,其上部分为 HEAD 即当前分支的修改
# 其下部分为 testing 修改
$ git commit -a -m 'Merge testing branch'
$ git log --all --oneline --graph
* e91a354 (HEAD -> master) Merge testing branch
|\
| * 3db9165 (testing) Modify and delete file
* | 068a3fd modify hot.txt
|/
* cf2ed48 Add test.txt file
* af2c062 (tag: v0.2) Modify directory
* aa32f04 (tag: v0.1) Add test.txt file
* 2f25228 (tag: v0.0.1) Initial master
# 以图形化的形式展现两分支的关系
3.3. 变基
另一种整合不同分支修改的方法,以下图为例。它会先提取在 experiment 分支下 C4 中引入的补丁和修改,然后在 master 分支的 C3 基础上再应用一次,从而完成变基操作。
git checkout experiment
git rebase master
# 在 experiment 分支下,将最新修改变基到 master 分支上
git checkout master
git merge experiment
# 然后再回到 master 分支做一次快进合并
变基与三方合并在查看提交历史时,变基会呈现一条线,而三方合并会先分叉又合并
三分支的变基例子
git rebase --onto master server client
# --onto 选项指选中 client 的修改,而不选择 server 的修改,然后将其变基到 master 上
# 这里它会找出 client 和 server 共同祖先之后的 client 修改,即 C8、C9
git checkout master
git merge client
# master 快进合并到 client 处
git rebase master server
# 将 server 变基到 master 上,参数 server 是 git checkout server 的缩写
git checkout master
git merge server
# master 快进到 server 处
3.4. 优选
优选就是将某分支的某个提交应用到当前分支上,类似于对特定的某次提交的变基
git cherry-pick e43a6
# 在 master 分支上,将 e43a6 拉取到 master 上
4. 远程仓库
$ git remote # 查看远程仓库
origin
$ git remote -v # 查看远程仓库及对应 URL
origin https://github.com/example/demo (fetch)
origin https://github.com/example/demo (push)
git remote add <shortname> <url>
# 添加远程仓库,之后就可以用 shortname 来代替 url
$ git remote add origin https://github.com/example/demo
git push <remote_name> <brach_name>
# 将分支的文件推送到远程仓库中
例:git push origin master
git push origin master:master
# 将本地的 master 分支推到远程仓库的 master 分支
git push --set-upstream origin master:master
# 将本地 master 与远程 master 绑定,这样就不用每次 push 时再加上了
git fetch origin
# 从远程仓库中获取本地未有的文件
# 但抓取的文件在工作目录还看不到,还需合并到本地的 master 分支才行
git merge master
git pull origin
# 获取+合并,执行后直接就能看到下拉取的文件了
在实际 fetch 或 push 远程仓库时,遇到 “Permission denied (publickey). Could not read from remote repository”,这是 git 还未与远程仓库建立连接,还需 github 上生成安全的 SSH 密钥才行。具体操作如下:
ssh-keygen -t rsa -C "youremail@example.com"
# 生成 sshkey,执行后按三次回车
然后会在 C:\Users\xxx\.ssh\id_rsa.pub (Windows)
; ~/.ssh/id_rsa.pub(Linux)
中看到生成的公钥。接着登录到 github 或 gitee 上,进入 SSH 栏,将 id_rsa.pub 的内容复制到 “key” 或 “公钥”,然后点击按钮输入账户密码生成 SSH公钥,成功后在 git 上就可访问到远程仓库了。
ssh -T git@gitee.com
# 在生成公钥后,也可用此命令来验证是否验证成功
# 同时它会添加到本机 ssh 可信列表,即 known_host 文件
值得注意的是,在 linux 下,要使用 cat 命令来查看 id_rsa.pub 文件。若要用 vim 查看的话,在复制到 gitee 上是一段段文本,从而导致密钥生成失败。
4.1. 远程操作的一些问题
当远程库被改时,在没有先拉取的情况下直接就推送,就会产生错误,提示远程库与本地不一致。所以要先拉取再推送以保证一致性
当在开发中有两个人同时对同一文件做出改动,就会出现之前那种冲突问题,那就要找到冲突文件并手动修改和重新提交、推送
5. IDEA 中使用 Git
创建本地仓库:在菜单栏 –> VCS –> Create git repo..
在对话框中选中项目目录,即可将其初始化。但其中的文件都是红色的,即都是未跟踪状态
目录或文件右键 –> Git –> Add filename 将文件添加至暂存区; 或者直接使用右上 git 图标栏,选中对勾(commit),之后就可在其中选择目录或文件,随后提交即可完成添加提交操作
点击右上的 push 图标,即可推送。首次会弹出对话框来绑定远程仓库的 url,确定后选择远程库的分支,确定即可
在下面菜单栏(Run, terminal..)中会有个 git 栏,它就是图形化的 git 命令。能够看到提交历史、控制台输出等
当然打开 Terminal 后,仍可使用 git 命令窗口来完成 git 管理
注:但由于我建库时生成了 readme 文档,从而导致本地库与远程库不一致而 push 失败。并且在拉取时,出现了”Can’t update” 和 “master has no tracked branch”, 随后经查阅使用 git pull origin main --allow-unrelated-histories
命令才成功拉取。而且由于 github 上的默认分支已经变为 main,所以还需注意修改。