git使用汇总

参考 廖雪峰的GIT教学
后期会自己添加一些额外的命令进来





git本地仓库基本结构

  • 工作区.git文件夹所在的目录,本地文件夹
  • .git文件夹:版本库
  • .git内的stage文件夹: 暂存区
    在这里插入图片描述

1. 本地GIT仓库基本操作

  • 首次使用git, 应该先指明全局git 用户信息. 直接打开Git bash, 输入

    • git config --global user.name "<用户名>"
    • git config --global user.email "<邮箱>"
      若想为某个仓库单独设置用户信息, 则在该仓库内打开git bash, 去掉--global, 然后指定信息即可
  • git init 在文件夹中打开git bash, 输入这个指令后, 根目录下就多了一个.git文件夹, 这是GIT的版本库

1.2 工作区操作

git status 查看工作区状态,告知你是否有文件变化, 比如新增文件, 删除文件, 文件内容变化, 哪些文件已经add, 哪些文件还没有被跟踪(从来没有add过, 或者是被.gitignore所忽略的文件)

git diff 查看工作区文件内文件的内容改动

git add <file> 把某个文件的 改动 add到暂存区(stage file)中, 多个文件则用空格隔开

git add . 把当前工作区所有文件 改动 add到stage,也可以 git add -A 或者 git add *他们的区别看这里

git reset . 取消暂存所有已修改的文件,让它们回到工作目录中未暂存的状态。具体来说,git reset . 会将当前目录下所有已经被 git add 命令添加到暂存区的文件,从暂存区中移除,使得这些文件的状态变成未暂存(也就是未添加)的状态。git reset . 不会撤销文件的修改,而只是将修改的文件从暂存区移除,恢复到工作目录中未暂存的状态

git commit -m "<备注信息>" 用于将已添加到暂存区中的文件改动提交到Git仓库中,并创建一个新的 提交记录
git commit --amend 同样是提交stage中的改动到仓库中, 不同的是改动将 合并到最新的提交记录内 , 不创建新的提交记录

git checkout -- <file> 撤销工作区的更改,让文件回到最近一次提交时的状态。如果文件已经添加到暂存区(stage区), 那么该命令会将文件恢复到暂存区的状态。如果文件还没有添加到暂存区,那么该命令会将文件恢复到最新的提交版本的状态。

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

1.3 本地仓库操作

git log or git log --pretty=oneline 显示git版本库所有提交记录, 该命令显示了提交的SHA哈希值、作者、提交日期、提交消息以及与该提交相关联的文件更改

HEAD指针: 指向当前所在分支最新一次提交的指针, 可以理解为是当前分支的别名. 当提交更改或创建新分支,Git会自动更新HEAD指向最新的提交。当你进行新的提交时,Git会将新的提交放在HEAD所指向的提交的后继节点,同时更改HEAD指向最新的提交。这样,HEAD就一直指向最新的提交,以表示当前分支的状态. 在Git中,可以使用"git log"命令来查看当前分支的提交历史记录,其中HEAD会显示在顶部。另外,可以使用"git checkout"命令来移动HEAD指针到其他分支或提交,从而切换到其他的代码状态。当HEAD指向一个特定的提交时,它被称为"detached HEAD"状态,此时不再与任何分支相关联。

git reset --hard <HEAD> 会重置工作区暂存区的内容,将它们恢复到最近一次提交时的状态. 需要注意它会丢弃当前工作区和暂存区的所有未提交的更改,包括添加、修改和删除的文件, 请谨慎使用–hard指令
git reset --hard <具体版本号> 回到指定版本的提交, 需要指定具体该版本的SHA哈希值(不用输入全部, 只需要前面几个字符即可). (当你回到某个具体的版本后, HEAD指针指向当前版本, 此时git log 也看不到当前提交版本的后面所有的版本了, 如果还想后悔, 在命令行窗口没有关闭的情况下, 找到之前命令记录, 如果还能找到那个版本号, 则还可以reset回该版本, 并且该版本之前的所有提交记录也都会恢复)

git reflog 后悔药. 显示本地Git仓库的 引用日志. 引用日志记录了Git仓库中引用的变化历史,包括分支、标签等,以及这些引用所指向的提交记录,包括HEAD的变化历史。可以使用git reflog命令找回误删的分支(可以reset到它)或提交记录,或者查找之前执行的Git命令历史记录.

引用(Reference): 指向一个Git对象(如提交记录)的指针,相当于一个别名或标签。Git中的每个引用都有一个名称,它们指向一个Git对象的SHA值。Git中最常见的引用类型:

  • 分支: 指向一系列Git提交记录的指针,表示一个独立的开发线。每个分支都有一个名称,并且可以随时切换到不同的分支上
  • 标签: 是指向特定Git提交记录的指针,通常用于标记版本发布。每个标签都有一个名称和一个描述,可以用于在Git仓库中标记重要的里程碑
  • HEAD: 指向当前正在工作的分支或提交记录,表示当前工作区所处的状态。
  • 远程跟踪引用: 是指向远程Git仓库中分支的指针,用于记录本地分支与远程分支之间的关联关系。

git diff <SHA1> <SHA2> --stat 对比两个版本的状态差异, 结果是简洁的统计信息,其中包括哪些文件发生了更改、文件的插入和删除的行数、文件的更改百分比等信息。适合快速查看代码库的变化趋势。
git diff <SHA1> <SHA2> 会显示详细的文件差异内容,包括每个文件中哪些行发生了改变、被删除或者被添加. 对大型代码库来说,输出结果非常长,不方便阅读。


2. 分支操作

详细请看廖雪峰的官方网站:创建与合并分支

查看现有分支信息

  • git branch 列出本地仓库所有分支, 并且在当前所在分支上标注星号
  • git branch -r 列出远程库所有分支
  • git branch -a 列出所有本地远程库的分支名称

分支,仅区分本地远程

创建/删除/切换分支

  • git branch <name> 创建新分支 (注意跟列出本地所有分支的区别, 仅在其后多了一个分支名称)
  • git branch -d <name> 删除分支
  • git branch -D <name> 强行删除分支(没有合并到主分支, 用-d删不掉)
  • git checkout <name> 切换到目标分支
  • git checkout -b <name> 创建并切换到一个新的分支

分支合并

  • git merge <name> 将指定分支的修改合并到当前分支中
    • 如果合并过程中发生冲突,Git 会将冲突标记出来,并提示你手动解决冲突。解决冲突后,可以使用git add命令将修改添加到暂存区,然后再使用git commit命令提交合并结果。再提交合并结果
    • 合并分支之前,最好先使用git pull同步该分支在远程仓库的最新提交版本,主要是为了避免冲突, 总之,保持当前分支的代码与远程仓库同步是一个好习惯,可以避免许多麻烦。

合并目标分支到的当前分支:git merge --no-ff -m "<information>" <branch> (关闭fast forward)


2.1 合并分支冲突解决

当两个分支的修改无法自动合并时,就会产生冲突。这通常发生在两个分支同时修改了同一个文件的相同部分,而 Git 无法确定应该采用哪个版本。

git status 告诉你哪些文件存在冲突,以及冲突的具体位置. 此时点开该冲突文件,冲突内容会被标记出来,删除<<<===>>>等内容,留下自己最终想要留下的代码即可. 解决冲突后, 用git add将解决后的冲突文件暂存, 解决完所有冲突后, 一次性git commit 提交本地库即可

git log --graph --pretty=oneline --abbrev-commit 这个命令可以显示 Git 仓库的提交历史,同时按照提交的分支和合并的情况画出图形, 可以很清晰的看到分支提交路径, 合并路径

请注意,当解决合并冲突时,应谨慎考虑所做的更改。如果您不确定如何解决冲突,请考虑在备份分支上尝试合并操作,以便能够撤消任何错误更改。

2.2 合并分支的fast forward概念

fast forward:git merge <name> 合并一个分支到当前分支, 并且该分支是基于当前支新增了一些修改, 则合并的操作仅仅是把当前分支的指针直接指向该分支. 如果此时删除该分支, 则我们根本看不出来我们是从一个分支合并过来的. 比如当前在master主分支上, 我们要开发一些新功能, 一般会用git checkout -b dev 创建一个dev分支, 完成功能开发, 测试无误后合并到master分支上. 那么如果是git checkout master切换到主分支上, 通过git merge dev把dev分支合并到当前的master分支上, 则默认执行 fast forward 合并. 在删除dev分支后, 用 git log 命令查看提交历史, 你根本就看不到dev分支曾经存在过. 用 git log --graph --pretty=oneline --abbrev-commit 也看不到合并操作的图形指示…

强烈建议--no-ff 参数来显式地指示 Git 执行不使用 fast forward 模式的合并,而是创建一个新的提交来合并两个分支的历史记录, 这样的好处是, 即使我们在合并dev分支到master分支之后, 删除了dev分支, 我们查看历史 依旧可以清晰明确的知道, 我们曾经从dev分支合并了一次.

在这里插入图片描述


2.3 stash储藏表

暂存区stage和储藏表stash,都是用于存放工作区的修改内容,不同的是

  • stage存放的内容已经编辑完成,即将commit
  • stash存放的内容还没编辑完,不准备commit,只是暂时要切换到其他分支做事,事后还会切回来继续工作

git stash:把当前分支工作区的修改内容隐藏到stash list中,工作区干净了,
git stash list:查看stash中的存储记录

想要从储藏室恢复之前工作区内容有两种方式

  • 分步:git stash apply恢复,git stash drop 手动删除stash中的记录
  • 一步:git stash pop

git cherry-pick <commit id>复制某个特定的提交到当前分支


3 远程库

3.1 创建自己的github远程库

GitHub支持两种协议进行代码的访问和推送,分别是HTTPSSH协议。

  • 使用HTTP协议进行访问和推送代码,需要每次操作都输入用户名和密码,而且在访问量较大时,速度会变慢。此外,使用HTTP协议也会有一些安全性的问题,比如传输过程中可能会被中间人攻击窃取账号密码等敏感信息。
  • 相比之下,使用SSH协议可以更加高效和安全地访问和推送代码。SSH协议通过公钥和私钥进行身份验证,可以避免每次都需要输入用户名和密码的问题,并且数据传输过程中也更加安全。克隆一个仓库, 比HTTP协议快上10倍不止
  • 总而言之, 尽可能使用SSH协议。但是需要注意的是,使用SSH协议需要事先配置好公钥和私钥,同时也需要在GitHub上添加公钥,才能够正常使用。

在C盘用户目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下面这一步

创建密钥: SSH密钥实际上是用于验证你的本地计算机和你在GitHub上的帐户之间的身份的一组密钥对。当你在GitHub上创建SSH密钥并将公钥添加到你的GitHub帐户时,你就可以使用该密钥对进行身份验证,以便在本地计算机和GitHub之间进行安全的通信。具体来说,当你向GitHub发送请求时,GitHub会使用你的公钥对请求进行加密,然后发送给你的本地计算机。本地计算机使用私钥对请求进行解密,从而证明请求来自你的GitHub帐户,并且你具有访问所请求资源的权限

  1. ssh-keygen -t rsa -C "<邮箱>" . -t rsa表示使用RSA算法生成密钥对,-C选项可以添加注释以帮助你识别密钥。在执行该命令后,会提示你输入密钥保存路径文件名,并提示你输入密码(可选)。你可以按照提示输入或一直回车保持默认。完成上述步骤后,你应该能在.ssh文件夹中看到id_rsaid_rsa.pub两个文件。其中,id_rsa是你的私钥文件,id_rsa.pub是你的公钥文件。
    在这里插入图片描述
  2. 进入github账户setting页面, 左边的“SSH and GPG keys”,点击"new SSH key"填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容

GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。


3.2 关联本地git仓库与远程github仓库

方法1:

  • github上创建空白仓库, 复制SSH地址
  • 本地新建文件夹, 用命令 git clone <ssh地址> 克隆仓库
  • 克隆操作会让Git自动把本地的master分支和远程的master分支对应起来

方法2:

  • 在github创建空白仓库后,复制SSH地址
  • git remote add origin <ssh地址> 直接将本地已经存在的GIT仓库与远程github仓库建立关联

3.3 远程库命令

  • git remote -v 查看远程库信息, 显示可以抓取和推送的地址。如果没有推送权限,就看不到push地址
  • git remote rm <远程库名字> 切断本地仓库与远程仓库的联系
  • $ git push <远程库名> <具体分支名> 简化版命令, 推送本地仓库的最新提交到远程库(如果还建立上游分支,则会报错, 提示先建立上游分支,才能使用简化命令)
  • git push -u origin master 使用-u参数时,Git会将本地分支推送到远程仓库的同时将远程分支(origin/master)设置为本地分支(master)的上游分支。这意味着,以后如果你在本地分支master中进行了更改,只需要执行 git push 命令,Git就会自动将更改推送到已关联的远程分支上。同样的如果你新开了一个分支dev, 在push dev分支的时候使用了 git push -u origin dev, 则后续的dev分支的推送, 也可以简化成 git push, 前提是你当前所在分支是dev.
  • git remote set-url origin <远程库地址> 如果github远程库的地址更改了,如更改github账户名,则会使本地仓库关联的远程库地址错误,因此需要运行此命令来更改远程库的地址

不一定要把本地分支全部往远程推送,哪些分支需要推送,哪些不需要呢?
master分支是主分支,因此要时刻与远程同步;
dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。


4. 多人协作

试图用git push origin <branch-name>推送自己的修改

  • 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull把远程库的最新改动合并到本地仓库
    • 如果合并有冲突,则解决冲突,并在本地提交;
    • 没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!
  • 如果git pull提示no tracking information,则说明本地创建的分支和远程分支的链接关系没有创建
  • git branch --set-upstream-to <branch-name> <远程库-name>/<branch-name>,建立本地分支和远程分支的关联
    • 不行就用这个:git branch --set-upstream-to=origin/<branch> master

git pullgit fetch 都是将远程仓库中的最新代码更新到本地仓库中,但它们之间有一些区别

  • git fetch 命令将远程仓库中的最新代码拉取到本地仓库中,但并不会自动合并本地代码和远程代码,需要使用 git merge 命令将它们合并。使用 git fetch 命令可以查看远程仓库中的最新变化,但是不会修改本地代码。因此,它是一种安全的方法,可以让您在合并之前先预览更改。
  • git pull 命令与 git fetch 类似,但它自动合并本地代码和远程代码。它首先运行 git fetch 命令,然后将获取到的远程分支自动合并到当前本地分支。如果本地分支与远程分支之间有冲突,git pull 命令会尝试自动解决冲突并进行合并,如果解决不了则需要手动解决。解决后,需要运行 git add 命令来标记文件已解决冲突,并运行 git commit 命令将其提交到本地仓库。

5 Rabase

git rebase 将一个分支的修改应用到另一个分支上。与git merge不同,它不是将分支合并到目标分支上,而是将目标分支上的修改移到当前分支上。

案例1:假设我们有两个分支,master 和 feature。在 feature 分支上有两个提交记录 C1 和 C2,而在 master 分支上也有两个提交记录 C3 和 C4,如下所示:
在这里插入图片描述
如果我们想将 feature 分支的提交历史移动到 master 分支后面,可以使用 git rebase 命令:
git checkout feature
git rebase master

在这里插入图片描述
可以看到,使用 git rebase 后,原本的提交记录 C1 和 C2 被移动到了 C3 和 C4 的后面,形成了新的提交记录 C1’ 和 C2’。这样做的好处是可以使提交历史更加清晰、线性,便于代码审查和维护。

如果直接在master分支上 执行 git rebase , 则默认是把本地master变基到远程库的master


6. 标签管理

创建标签

  • 首先,切换到需要创建标签的分支上:git checkout <branch-name>
  • git tag <tag-name> <commit-id> 创建标签,不指定<commit-id>则创建在最新commit上,
  • git tag -a <tag-name> -m "..." <commit-id> 创建带说明的标签:
  • git tag 列出所有标签,按照首字母排序
  • git show <tagname> 查看具体标签的信息

标签操作

  • 删除本地标签: git tag -d <tag-name>
  • 推送单个标签到远程:git push <远程库名> <tag-name>
  • 推送所有标签到远程:git push <远程库名> --tags

想删除远程标签

  • 先删除本地标签:git tag -d <tag-name>
  • 再删除远程标签:git push <远程库名>:refs/tags/v0.9 依然是push操作,但命令不同

7 github Fork

在这里插入图片描述

功能介绍

  • 当你Fork一个项目时,会将原有项目的代码库全部克隆到自己的GitHub账户下,并自动创建一个与原有项目同名的新项目。你可以在自己的项目中进行任何修改,并向自己的远程github仓库提交

  • 自己拥有Fork后的仓库的读写权限, 如果不fork,仅仅是clone原作者的仓库到本地, 你是不能推送自己的代码改动到远程仓库的.

  • fork仓库后, 可以pull request给原作者的仓库来贡献代码

同步原作者仓库的最新提交, 步骤:

  • 首先需要将原作者的仓库添加为自己的本地仓库的 另一个远程仓库(还有一个远程库是自己fork下来的)

    git remote add upstream <原作者的仓库地址>
    
  • 然后从原作者的仓库中拉取最新的代码

    git fetch upstream
    
  • 将本地代码切换到主分支(通常是 master 分支)

    git checkout master
    
  • 将本地的主分支与原作者的主分支合并, 这将把原作者的最新代码合并到你的本地主分支

    git merge upstream/master
    
  • 如果本地主分支有冲突,需要手动解决冲突并提交到本地库

  • 最后将更新后的代码推送到 自己fork的远程仓库

    git push origin master
    

8 克隆带有子模块的github仓库

git clone --recursive <地址>git clone --recurse-submodules <地址> 的功能类似,都是用于克隆带有子模块的仓库,但是两者之间有一些差别

  • git clone --recursive 命令会在克隆完毕后自动初始化子模块,但是如果子模块还包含子模块的话,
    需要再手动初始化 git submodule update --init --recursive

  • git clone --recurse-submodules 命令会在克隆完毕后自动递归初始化所有子模块(包括子模块的子模块),可以避免漏掉子模块的情况。因此还是推荐使用这种方式

出错1: 如果子模块实在是克隆不下来, 可以手动下载子模块的代码zip解压后并放到对应的文件夹中。不过,需要进行一些额外的操作才能让该项目正常运行。

  • 将代码放到子模块对应的文件夹中, 打开该子模块的文件夹,执行以下指令:

    git add .
    git commit -m "Add manually downloaded submodule code"
    

    这将手动下载的代码提交到子模块的Git仓库中。

  • 接下来,你需要将该子模块的Git仓库与父项目进行关联。进入父项目的根目录,执行以下指令:

    git submodule add <子模块的Git仓库地址> <子模块在父项目中的路径>
    

    其中,<子模块的Git仓库地址>是子模块的Git仓库地址,<子模块在父项目中的路径>是子模块在父项目中的相对路径。

  • 提交修改到父项目的Git仓库中:

    git add .
    git commit -m "Add manually downloaded submodule"
    

    这样,就完成了手动添加子模块的操作。注意,如果子模块中还有其他子模块,需要按照相同的方式手动添加并提交修改。

出错2: 如果已经克隆了仓库,没有递归克隆其子模块,可以通过以下方式补救

git submodule init
git submodule update

9 在自己代码库使用第三方库(来自github某个仓库)的最好方式

  • 复制第三方库的HTTP链接,在本地仓库根目录打开命令行,以下命令:
    git submodule add <http链接> <目标路径>
    
    目标路径是你想要存放这个仓库代码的地方,这个路径是以当前目录为起始点的子路径
  • 如果克隆成功,目录下会多出一个.gitmodules.txt文件,用于记录你的仓库所引用的其他github仓库的地址以及存放路径。可以用文本编辑器打开看看它的内容
    在这里插入图片描述

这样的方式最明显的好处是:

  • 可以方便地将第三方库的更新合并到自己代码库中。因为可以通过 Git 子模块跟踪第三方库的变化,从而能够快速、方便地将其更新到最新版本
  • 可以更好地管理依赖关系。使用 Git 子模块,可以将所有依赖项的源代码集中在一个地方,并轻松地共享依赖项。

猜你喜欢

转载自blog.csdn.net/Motarookie/article/details/127692140