Git 学习笔记

261 阅读11分钟

1.创建版本库

以下为实际学习时,依次执行的语句。

mkdir LearningGit

cd LearningGit

git init //将当前目录变为Git可管理的仓库

vim read.txt

git add read.txt //将文件添加到版本库,实际上是添加到暂存区 stage

git config --global user.email "zhu_lilong@qq.com"

git config --global user.name "zhu_lilong"

一次性将暂存区的所有内容提交到唯一的main / master分支。

提交文件,一次可提交多个,因此之前可添加多个文件。

git commit -m "add read.txt and readme.txt"

2.版本回退

vim readme.txt //此处修改此文件

git status //输出仓库当前的状态,例如仓库中是否有文件被修改

git diff //若仓库中文件被修改,可输出文件更改的信息

git diff master    //查看当前分支与master分支的差异

git add readme.txt

git commit -m "add a sentence in readme.txt"

git log //显示从日期最近到最远的提交日志,亦即显示当前分支commit的历史

image.png

git log --pretty=oneline //精简日志信息

Git 内部有一个指向commit版本的指针HEAD,恢复到某个版本只需要修改指针指向。

严格来说,HEAD 指向 当前分支, 当前分支 指向当前提交点。

git reset --hard HEAD~1 //回退到往前第 1 个版本

git reset --hard 22ba //恢复到指定版本号(使用SHA1计算得出)的版本

git reflog //记录每一次改动当前版本库的命令,输出结果中第一个参数是版本号的前几位

image.png

3.管理修改

Git 跟踪管理的是修改,而非文件。

每次修改,如果不通过git add添加到暂存区,那么就不会被提交到主分支中。

vim list.txt //修改文件

git add list.txt

vim list.txt //再次修改文件

git commit -m "Change to three lists."

git status //会发现第二次修改未被提交

上述操作过程如下:

第一次修改 -> git add -> 第二次修改 -> git commit

Git管理的是修改,当使用git add命令后,在工作区的第一次修改被放入暂存区,准备提交,但是,在工作区的第二次修改并没有放入暂存区,所以,git commit只负责把暂存区的修改提交了,也就是第一次的修改被提交了,第二次的修改不会被提交。

git diff HEAD -- list.txt //查看工作区与版本库中最新版本之间的区别

git add list.txt

git commit -m "add two lists to List"

git diff HEAD -- list.txt //二者之间已无区别

4.撤销修改

vim list.txt //修改 list.txt

git checkout -- list.txt // 或者 git restore list.txt

命令git checkout -- list.txt的作用是把list.txt文件在工作区的修改全部撤销,这里有两种情况:

一种是list.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;

另一种是list.txt已经被添加到暂存区,而后又作了修改,现在,撤销修改就回到最初刚被添加到暂存区后的状态。

总之,就是让这个文件回到最近一次git commitgit add时的状态。

小结如下:

1)当改乱了工作区某个文件的内容后,想直接丢弃工作区的修改时,用命令git checkout -- file

2)当不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD~1 read.txt //回退文件的版本到上一个版本,就回到了第一种情况,第二步按第一种情况进行操作。

3)当已经提交了不合适的修改到版本库时,想要撤销本次提交,可回退版本,不过前提是没有推送到远程库。

5.删除文件

vim test.txt

git add test.txt

git commit -m "add test.txt"

rm test.txt

ls //已从工作区移除文件

git ls-files //查看版本库中的文件

//前提是版本库中存在目标文件

git restore test.txt //git checkout -- test.txt //“删除”也属于“修改”,因此仍可以使用相应的撤销修改命令

rm test.txt

git rm test.txt

git ls-files //已从版本库中移除文件

git commit -m "rm test.txt" //提交到当前分支

6.远程仓库

将本地库与Github上的远程库 origin 相关联,库名可修改。

git remote add origin https://github.com/userName/LearningGit.git

把本地库分支master / main的内容推送到远程库。

由于远程库是空的,所以第一次推送时,加上了-u参数,Git不但会把本地的master分支内容推送到远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后推送或者拉取时就可以简化命令。

git push -u origin master //密码使用 token

//若远程没有 feature 分支,则会自动创建相应分支,但不会把本地分支与feature分支关联起来

git push origin feature //后续推送其他分支时,便不需再加上 -u 参数

git remote -v //查看远程库信息

git branch -vv //查看本地分支对应的远程分支

删除远程库,仅是解除了本地库和远程库的绑定关系,并不是物理上删除了远程库。远程库本身并没有任何改动。要真正删除远程库,需要登录到GitHub进行删除。

git remote rm origin

将远程库克隆到本地。

git clone git@github.com:userName/NewRepository.git

仅克隆指定的远程分支到本地。

git clone --branch branchname --single-branch remote-repo-url

7.分支管理

查看分支:git branch

创建分支:git branch <name>

切换分支:git checkout <name>或者git switch <name>

创建+切换分支:git checkout -b <name>或者git switch -c <name>

合并某分支到当前分支:git merge <name> //可以是本地分支,也可以是远程分支

删除分支:git branch -d <name>

删除远程分支:git push origin --delete branchName

解决冲突:

当Git无法自动合并分支时,就必须首先解决两个分支之间的冲突。解决冲突后,再提交,最后完成合并。

解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。

git log --graph --pretty=oneline //输出分支合并图

image.png

合并模式:

git switch -c test

vim read.txt //修改文件

git add read.txt

git commit -m "Something changes in read.txt"

git switch main

git merge --no-ff -m "merge with no-ff" test //禁用 Fast-forward 合并模式

以普通模式合并,在分支历史/提交日志中可以看到被合并分支的提交历史。

而对于 Fast-forward 合并模式,则不会显示被合并分支的提交历史。

git log --graph --pretty=oneline --abbrev-commit

git branch -d test

保存分支工作现场:

vim read.txt //添加一个bug

git add read.txt

git commit -m "add a bug in read.txt"

git switch -c dev

// do something in dev

vim read.txt // fix the bug

git add read.txt

git commit -m "fix a bug in read,txt"

image.png

git stash //保存工作现场

git switch main

git cherry-pick 8701063 // 复制特定的提交到当前分支

vim read.txt //可观察到,bug已被修复

git switch dev

git stash list //查看保存的工作现场的列表

git stash apply stash@{0} //恢复到指定的工作现场

git stash drop stash@{0} //删除指定的已存储的工作现场

开发新功能时,最好新建一个feature分支。

当feature分支未被合并时,若想删除feature分支,则需要加上 -D 参数。

git branch -D feature

多人协作:

将远程库克隆到本地的指定目录中。

git clone git@github.com:userName/NewRepository.git NewClone

git branch //默认情况下,只能看到 main 分支

若想在其他分支上进行开发,必须创建远程库的相应分支到本地。

远程库的名称可直接使用 origin。

git switch -c feature origin/feature

git push origin branchName:branchName //推送本地的branchName(冒号前面的)分支到远程origin的branchName(冒号后面的)分支(没有会自动创建)

多人协作的工作模式:

  1. 首先,尝试使用git push origin <branch-name>推送自己的修改;

  2. 如果推送失败,则因为远程分支比本地分支更新(可能因为他人已经推送过了),需要先用git pull试图合并;

    git pull origin feature:feature(将远程库的feature分支拉取过来,与本地分支feature合并,可用于更新本地分支)

    其实就是 git fetch 与 git merge FETCH_HEAD的简写

  3. 如果合并有冲突,则先解决冲突,而后在本地提交;

    git diff --name-only --diff-filter=U 显示冲突文件。

    <<<<<<<到=======是在当前分支合并之前的文件内容 。

    =======到>>>>>>> 是在其它分支下修改的内容。

  4. 没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!

如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to=origin/<branch-name> <branch-name>

8.标签管理

标签是版本库的快照,它唯一指向打标签时刻的版本。标签不能移动,与相应的commit编号绑定在一起。

标签是和某个commit绑定的。如果这个commit既出现在master分支,又出现在dev分支,那么在这两个分支上都可以看到此标签。

commit编号是由SHA1计算出的一长串字符,难以记忆,而标签容易记忆。

git tag vc //给当前分支所处的commit版本打标签

git tag va b4b8 //给指定commit编号的版本打标签,同一个版本库可以打多个标签

git tag -a vr -m "vr for b4b8" b4b8 //给指定 commit 编号的版本打标签,并添加标签说明

git show vr //显示标签信息

git tag //显示所有标签,默认按标签字符的顺序排序,而非按照commit编号或标签的创建时间进行排序

命令git push origin <tagname>可以推送一个本地标签;

命令git push origin --tags可以推送全部未推送过的本地标签;

命令git tag -d <tagname>可以删除一个本地标签,但远程标签不受影响;

命令git push origin :refs/tags/<tagname>可以删除一个远程标签,但本地标签不受影响。

将远端仓库的特定tag同步到本地,并创建分支:

# 获取远端的名为tagname的tag到本地,名字不变保存为本地tag 
git fetch origin tag tagname
# 从某一个名为tagname的tag创建一个新分支 new-branch-name
git branch new-branch-name tagname

9.注意事项

1)在执行相关 git 语句时,本地仓库可能与远程仓库不同步,远程仓库自身的改动 A 并不会自动同步到本地仓库。因此关于改动 A 所对应的本地操作,可能无法执行。

 例如在 A 中,远程仓库可能新建了一个分支 newBranch,但是本地仓库并未同步此改动。所以当新建远程分支 newBranch 的本地分支时,会报错 invalid reference。此种情况下,可首先执行 git fetch 同步远程仓库的改动,再进行相关操作。

git switch -c feature origin/feature 拉取的本地分支不一定是最新版本的 origin/feature 分支的原因亦如上。

2)“Changes to commit”: 新文件会被自动添加到暂存区,此处会列出位于暂存区的新文件。

 "Changes not staged for commit": 若修改了在之前已经被添加到仓库或暂存区的文件,则会在此处列出被修改的文件。

 "Untracked files": 仅位于工作区的新文件(例如若手动将新文件从暂存区移除,则新文件会在此处被列出)。

image.png

3)已配置的 ssh key 位于 ~/.ssh/id_rsa.pub 中。

4)修改本地最近一次的 commit 信息:git commit --amend

5)git revert:

git revert会生成一个“反向操作”,动过动作反转实现代码回滚。这也正是git revertgit reset的最大区别。

git revert操作没有删除已提交的commit,而是用一套反转代码将其覆盖,所以从语义上来讲开发者之前提交的commit已经完全合入master。即 master 分支存在两套代码,其一是已提交的 feature 功能的代码,其二是用于撤销新增功能的代码。

当在 B 分支上把 A merge 到 B 中,那么 B 就是 merge commit 的 parent1,而 A 是 parent2。

-m 属性用于显式地指明以哪一个 parent 为主线。

// 以 parent1 为主线,撤销 parent2 相较于 parent1 的修改
// cae5381 为 MR Commit
git revert cae5381 -m 1

当 revert 了 MR Commit 时,会 revert 该 MR 对应的所有提交记录。

参考文章

  1. Git 教程
  2. 如何将远端仓库的特定tag同步到本地,并创建分支
  3. 彻底搞懂 Git-Rebase
  4. 如何 Git Clone 指定分支
  5. git-修改commit信息
  6. 2.2 Git 基础 - 记录每次更新到仓库
  7. 当你决定去 revert 一个merge commit
  8. git revert merge完全指南