My Blog

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 基础上再应用一次,从而完成变基操作。

rebase

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 处

rebase_client

git rebase master server
# 将 server 变基到 master 上,参数 server 是 git checkout server 的缩写

git checkout master
git merge server
# master 快进到 server 处

rebase_server

3.4. 优选

优选就是将某分支的某个提交应用到当前分支上,类似于对特定的某次提交的变基

git cherry-pick e43a6
# 在 master 分支上,将 e43a6 拉取到 master 上

cherry


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 文件

sshkey

值得注意的是,在 linux 下,要使用 cat 命令来查看 id_rsa.pub 文件。若要用 vim 查看的话,在复制到 gitee 上是一段段文本,从而导致密钥生成失败。

4.1. 远程操作的一些问题

  1. 当远程库被改时,在没有先拉取的情况下直接就推送,就会产生错误,提示远程库与本地不一致。所以要先拉取再推送以保证一致性

  2. 当在开发中有两个人同时对同一文件做出改动,就会出现之前那种冲突问题,那就要找到冲突文件并手动修改和重新提交、推送

5. IDEA 中使用 Git

  1. 创建本地仓库:在菜单栏 –> VCS –> Create git repo..

  2. 在对话框中选中项目目录,即可将其初始化。但其中的文件都是红色的,即都是未跟踪状态

  3. 目录或文件右键 –> Git –> Add filename 将文件添加至暂存区; 或者直接使用右上 git 图标栏,选中对勾(commit),之后就可在其中选择目录或文件,随后提交即可完成添加提交操作

idea_git

  1. 点击右上的 push 图标,即可推送。首次会弹出对话框来绑定远程仓库的 url,确定后选择远程库的分支,确定即可

  2. 在下面菜单栏(Run, terminal..)中会有个 git 栏,它就是图形化的 git 命令。能够看到提交历史、控制台输出等

  3. 当然打开 Terminal 后,仍可使用 git 命令窗口来完成 git 管理

注:但由于我建库时生成了 readme 文档,从而导致本地库与远程库不一致而 push 失败。并且在拉取时,出现了”Can’t update” 和 “master has no tracked branch”, 随后经查阅使用 git pull origin main --allow-unrelated-histories 命令才成功拉取。而且由于 github 上的默认分支已经变为 main,所以还需注意修改。

别人的 idea git 使用介绍