git:本地分支与远程分支

在开发软件时,可能有多个人同时为一个软件开发,可能同时存在多个release版本,并且需要对各个版本进行维护,而git的分支功能就可以支持同时进行多个功能的开发和版本管理

什么是分支?

Git 保存的不是文件的变化或者差异,而是一系列不同时刻的 快照 。

  • git仓库的所有提交节点之间的关系,其实就是一棵树。所以一个分支也可以看成是树上的一条链路。
  • 如果说分支是一条链路的话,那么这个链路上的每一个节点就是一个commit提交,commit提交相当于快照或者游戏存档
    • 一个branch上有多个commit,一个游戏也可以有多个存档,但是当下显然只能加载一个。
    • 所以git当中用一个指针指向当前加载的commit,也就是说纵向来看一个分支代表的是一连串的提交,但在git当中我们使用的分支其实是一个指针,一个在commit当中切换的指针

深度理解怎么形成分支的

  • 一开始的时候我们只有默认分支master,它指向当前的一个提交
    在这里插入图片描述
  • 现在我们使用git branch test命令创建一个测试分支,执行之后,其实只不过是多了一个指针也指向当前的commit。git当中的结构变成这样:
    在这里插入图片描述
  • 当我们在test分支上做了改动提交之后,git会产生一个新的提交,并且移动test指针,而master指针会留在原地
    在这里插入图片描述
  • 如果我们再回到master也进行了改动和提交之后,又会产生新的节点,并且这个节点会和test的节点区分开,形成新的链路,于是就形成了一棵树的样子
    在这里插入图片描述

怎么知道我们在哪个分支的哪个提交上?

有一个问题是git怎么知道我们当前的代码在哪里呢?即使知道了代码在哪个分支上,又怎么确定在哪一个节点呢?我们是如何在git提交树上前后移动的呢?

git内部还有一个特殊的指针叫做HEAD。HEAD指向的是现在使用中的分支的最后一次更新。

  • 通常, HEAD 不直接引用单个提交。相反,它指向一个分支,并间接引用该分支中的最新提交。
  • 每次提交都会生成一个hash值。我们可以通过hash值来确定提交记录,head可以看成是一个指针,它指向你正在其基础上进行工作的提交记录,也就是说HEAD总是指向当前分支上最近一次提交记录。通常默认指向master分支的最后一次更新
  • 当我们提交代码的时候,不止只有分支的这些指针会往前移动,HEAD指针也会随着移动。通过移动HEAD,就可以变更使用的分支

大多数修改提交树的Git命令都是从改变HEAD的指向开始的

如何查看HEAD:

  • Git 中的 HEAD 可以理解为一个指针,我们可以在命令行中输入 cat .git/HEAD 查看当前 HEAD 指向哪儿,一般它指向当前工作目录所在分支的最新提交。
cat .git/HEAD
ref: refs/heads/<branch name>  // 正常
cad0be9ceb89f474c39360c4de337d4a8194cab0 // 游离状态
  • 如果HEAD指向的是一个引用,可以通过git symbolic-ref HEAD查看它的指向

怎么分离head: 分离HEAD就是让其指向了某个具体的commit id而不是分支名。git checkot就是用来分离HEAD的

有两种分离方法:

  • 我们可以通过git checkout切换到任意分支,任意节点位置(通过commit id来确定节点位置)
    • 这个commit id就是刚刚说的hash值。
      • 我们可以通过git log来查看提交记录的hash值
      • git对hash的处理很智能,我们只需要提供唯一标识提交记录的前几个字符就可以
    • 进行checkout后,git会从工作树还原向目标分支提交的修改内容,checkout之后的提交记录将被追加到目标分支
  • 但是通过hash值指定提交记录很不方便,所以git引入了相对引用,比如:
    • 通过^向上移动1个提交记录
    • 使用~<num> 向上移动n个提交记录,比如~3

本地分支与远程分支

我们有两种分支:

  • 本地分支
  • 远程分支
    • 远程跟踪分支是远程分支状态的引用。
    • 它们以<remote>/</branch>的形式命名。

对应的,我们有两种开发方式:

默认情况下:

  • master 是当你运行 git init 时默认的起始分支名字,是本地仓库的主分支
    • 第一种开发方式:开发时,你可以在本地创建一个分支,假设叫做issue,开发完成之后,就推送到远程
  • origin是当你运行 git clone 时默认的远程仓库名字,是远程仓库的主分支
    • 在本地开发完成之后,你可以把你的issue分支推送到远程,这时候远程仓库中就有一个origin/issue
    • 本地的分支并不会自动与远程仓库同步,你必须显示的推送想要分享的分支
    • 另外一种开发方式是,在远程开好分支,本地直接拉下来,然后在本地修改完成之后,再显示push到远程。

(1)在远程开好分支,本地直接拉下来;

git checkout -b feature-branch origin/feature-branch    //检出远程的feature-branch分支到本地

(2)本地开好分支,推送到远程.

$  git checkout -b developer_gen3_new_branch_name    //在本地创建分支
$  git push --set-upstream origin  developer_gen3_new_branch_name    //推送到远程

语法

创建并切换分支:

  • git branch + 分支名字:创建分支
    • 创建本质的本质是创建一个可以移动的新的指针
      • 此时这个指针指向当前的commit,它们指向相同的提交历史
      • 分支本质上是一个指针。
      • git 的分支只是简单的指向某个提交记录
    • 分支相当于:“我想基于这个提交以及它的所有父提交进行新的工作”
    • 使用建议:早建分支|多用分支
      • 这是因为即使创建再多的分支也不会造成储存或者内存上的开销,
      • 并且按逻辑分解工作到不同的分支比维护那些特别臃肿的分支简单多了
  • git checkout -b <分支名> :创建并切换到新的分支

在分支树上移动

  • git checkout<分支名>: 切换到分支

查看分支:

  • git branch
    • 显示当前所有(本地)的分支。
    • 前面有*表示当前分支。这意味着如果当前修改了,那么就基础当前分支向前移动
  • git branch -a:查看全部分支(包含本地和远程)
  • git branch -v:查看每一个(本地)分支的最后一次提交
  • git branch --merged
    • 查看哪些(本地)分支已经合并到当前(本地)分支
    • 在这个列表中分支名字前没有 * 号的分支通常可以使用 git branch -d 删除掉:你已经将它们的工作整合到了另一个分支,所以并不会失去任何东西。
  • git branch --no-merged : 查看哪些(本地)分支还没有合并到当前(本地)分支
    • 因为它包含了还未合并的工作,尝试使用 git branch -d 命令删除它时会失败
    • 如果真的想要删除分支并丢掉那些工作,如同帮助信息里所指出的,可以使用 -D 选项强制删除它。
  • git branch --no-merged master:查看当前未合并到master分支的有哪些?
  • git branch --merged master:查看当前已合并到master分支的有哪些?

提交分支:

  • 使用场景:当你在当前分支做了一些修改之后希望暂时记录所有改变时
  • git commit:提交本地的修改
    • git 仓库中的提交记录保存的是你目录下所有文件的快照
    • git 希望提交记录尽可能轻量,因此你每次提交时,它并不会盲目的复制整个目录。条件允许的情况下,它会将当前版本与仓库中的上一个版本进行对比,并将所有差异打包到一起作为一个提交记录
      • 在进行提交操作时,git会保存一个提交对象,该提交对象会包含一个指向暂存内容快照的指针,以及包含了作者的姓名和邮箱、提交时输入的信息以及指向它的父对象的最终。
      • git还保存了提交的历史记录。首次提交时没有父对象,普通提交操作产生的提交对象有一个父对象,而由多个分支合并产生的提交对象有多个父对象
    • 执行提交时,系统会要求输入提交信息。请务必输入提交信息,因为在空白的状态下执行提交会失败的。
    • 请以这种格式填写提交信息:
      • 第一行是不超过50个字提交修改内容的摘要
      • 然后空一行
      • 罗列出改动原因、主要变动、以及需要注意的问题
      • 最后,提供对应的网址(比如Bug ticket)。

合并分支:

  • 使用场景:新建一个分支,在其上开发某个新功能,开发完成之后合并回主线
  • 合并分支有两种方法:
    • git merge
      • 在git中合并两个分支时会产生一个特殊的提交记录,它有两个父节点。
      • 相当于:我要把两个父节点本身以及它们所有的祖先都包含进来。
    • git rebase
      • rebase实际上是取出一系列的提交记录,“复制”它们。然后在另外一个地方逐个放下去
      • rebase的优势是可以创建更线性的提交历史。
        • 只允许使用rebase的话,代码库的提交历史将变得十分清晰。
        • 使用rebase可以将某个分支上的工作直接移动到另一个分支上,移动之后会使得两个分支的功能看起来像是顺序开发的,但是实际上它们是并行开发的

删除分支:

  • git branch -d [branchname]:删除本地已合并的分支
  • git push origin --delete [branchname]:删除远程分支
    • 在删除远程分支时,同名的本地分支并不会被删除,所以还需要单独删除本地同名分支
  • git fetch -p:清理本地无效分支(远程已删除本地没删除的分支)
  • git branch | grep 'branchName':如果分支太多,还可以用此命令进行分支模糊查找

理解

默认情况下,我们在master分支,如果不切换分支的话,所有的操作都是在master分支上:
在这里插入图片描述

git branch:创建分支

本来我们是master分支,然后我们执行下面命令

git branch testing

就会创建一个testing分支。此时两个分支都有相同的提交记录
在这里插入图片描述
这条命令做了两件事。

  • 一是使 HEAD 指回 master 分支
  • 二是将工作目录恢复成 master 分支所指向的快照内容。

此时,我们位于master分支上,HEAD指向master分支的最后一次提交(通过HEAD指针知道我们位于哪一个分支上)
在这里插入图片描述
在这里插入图片描述

git branch:查看(本地)分支

显示当前所有(本地)的分支

不指定参数直接执行branch命令的话,可以显示分支列表。 前面有*的就是现在的分支。

$ git branch  #显示当前所有(本地)的分支。 前面有*表示当前分支
  iss53
* master  # 这意味着如果在这时候提交,master 分支将会随着新的工作向前移动
  testing

查看每一个(本地)分支的最后一次提交

$ git branch -v     #查看每一个(本地)分支的最后一次提交
  iss53   93b412c fix javascript issue
 * master  7a98805 Merge branch 'iss53'
  testing 782fd34 add scott to the author list in the readmes

查看哪些(本地)分支已经合并到当前(本地)分支

$ git branch --merged
  iss53
 * master
  • 因为之前已经合并了 iss53 分支,所以现在看到它在列表中。
  • 可以将iss53删除,因为该分支已经合并了

查看哪些(本地)分支还没有合并到当前(本地)分支

$ git branch -d testing  # 删除本地已合并的分支
error: The branch 'testing' is not fully merged.
If you are sure you want to delete it, run 'git branch -D testing'.
  • 因为它包含了还未合并的工作,尝试使用 git branch -d 命令删除它时会失败
  • 如果真的想要删除分支并丢掉那些工作,如同帮助信息里所指出的,可以使用 -D 选项强制删除它。

git commit:提交分支

git commit作用

git commit 命令将暂存区内容添加到本地仓库中(基于当前分支生成一个快照,head指向最新的快照)。

  • 当前状态如下图:
    在这里插入图片描述
  • 我们做一些修改,然后git add && git commit。可以看到基于当前分支生成了一个快照
    在这里插入图片描述

提交消息可能存在很多拼写错误, 你想修改最近的commit的log,应该怎么办?

  • git commit --amend,该命令将打开你的编辑器,并允许你更改最后一次提交消息

git log:查看提交历史/commit id

查看本地仓库提交历史

git log,可以查看提交历史

  • 默认按照时间先后顺序列出所有的提交,最近的更新排在最上面
  • 列出每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明。

在这里插入图片描述

如果想要不同于默认格式的方式展示提交历史

  • 可以使用--pretty。选项有onelineshort,full 和 fuller
git log --pretty=oneline

在这里插入图片描述

  • format ,可以定制记录的显示格式
$ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 6 years ago : changed the version number
085bb3b - Scott Chacon, 6 years ago : removed unnecessary test
a11bef0 - Scott Chacon, 6 years ago : first commit

$ git log --pretty=format:"%h %s" --graph
* 2d3acf9 ignore errors from SIGCHLD on trap
*  5e3ee11 Merge branch 'master' of git://github.com/dustin/grit
|\
| * 420eac9 Added a method for getting the current branch.
* | 30e367c timeout code and tests
* | 5a09431 add timeout protection to grit
* | e1193f8 support for heads with slashes in them
|/
* d6016bc require time for xmlschema
*  11d191e Merge branch 'defunkt' into local
%H提交的完整哈希值
%h提交的简写哈希值
%T树的完整哈希值
%t树的简写哈希值
%P父提交的完整哈希值
%p父提交的简写哈希值
%an作者名字
%ae作者的电子邮件地址
%ad作者修订日期(可以用 --date=选项 来定制格式)
%ar作者修订日期,按多久以前的方式显示
%cn提交者的名字
%ce提交者的电子邮件地址
%cd提交日期
%cr提交日期(距今多长时间)
%s提交说明

每次提交的简略统计信息

git log --stat
在这里插入图片描述

git log --oneline --decorate

在这里插入图片描述

  • 我们可以用git log 命令查看各个分支当前所指的对象。 提供这一功能的参数是 --decorate。
$ git log --oneline --decorate
f30ab (HEAD -> master, testing) add feature #32 - ability to add new formats to the central interface
34ac2 Fixed bug #1328 - stack overflow under certain conditions
98ca9 The initial commit of my project
  • 可以看到当前 master 和 testing 分支均指向校验和以 f30ab 开头的提交对象。

查看远程仓库提交历史

$ git branch -a   # 查看全部分支(包含本地和远程)
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/develop
  remotes/origin/master


$ git log remotes/origin/master  # (origin/master这个都是默认的远程仓库和分支,可以自己改成想看的仓库和想看的分支)
$ git log remotes/origin/develop

当然如果你的本地很久没有更新过远程仓库的信息了,看到的日志可能就不是最新的;

所以在查看之前需要先运行git fetch 或者git fetch origin。

git checkout:切换分支

切换分支(git checkout)的本质是将head指向另一个提交记录,可以通过控制HEAD在分支树上移动。

步骤

  1. 切换到某个分支上
  • 这时head指针将会指向issue1分支的最后一次commit
$ git checkout issue1
Switched to branch 'issue1'

在这里插入图片描述

  1. 在当前分支上做一些修改

  2. 提交

$ git commit -m "添加add的说明"
  • head分支将会随着提交而在commit上移动
    在这里插入图片描述

原理

git checkout testing

这样 HEAD 就指向 testing 分支了。
在这里插入图片描述

为什么要git checkout 呢?

假设我们当前分支结构是这样的:

在这里插入图片描述

也就是说当前有master分支和testing分支,当前位于testing分支上。

假如我们做了一些修改,然后再次提交

$ git commit -a -m 'made a change'

此时,分支图如下:

在这里插入图片描述
即testing分支向前移动了,但是master分支没有。

然后我们切换回checkout

$ git checkout master

在这里插入图片描述
这条命令做了两件事:

  • 一是使 HEAD 指回 master 分支
  • 二是将工作目录恢复成 master 分支所指向的快照内容。

也就是说,你现在做修改的话,项目将始于一个较旧的版本。 本质上来讲,这就是忽略 testing 分支所做的修改,以便于向另一个方向进行开发。

在切换分支时,一定要注意你工作目录里的文件会被改变。 如果是切换到一个较旧的分支,你的工作目录会恢复到该分支最后一次提交时的样子。 如果 Git 不能干净利落地完成这个任务,它将禁止切换分支。

我们不妨再稍微做些修改并提交:

$ git commit -a -m 'made other changes'

现在,这个项目的提交历史已经产生了分叉

在这里插入图片描述
你可以在不同分支间不断地来回切换和工作,并在时机成熟时将它们合并起来。 而所有这些工作,你需要的命令只有 branch、checkout 和 commit。

实验

分离HEAD:如何理解HEAD总是指向当前分支上最近一次提交记录

如下图Git仓库中: 当前正位于主分支main上,main分支最近一次提交记录为C1

在这里插入图片描述

  • 那么,此时HEAD状态位于哪里呢?因为,HEAD通常情况下都是指向分支名的, 而分支名总是指向当前分支上最近一次提交记录, 因此,当前的状态为:HEAD->main–>C1,就是说,HEAD指向main,main指向C1

在这里插入图片描述

接下来,我们分离HEAD,分离HEAD就是让其指向了某个具体的commit id而不是branch name,执行命令git checkout C1。 此时“HEAD–>C1”

在这里插入图片描述

游离HEAD:分离HEAD到底是什么意思

游离的HEAD指针:

  • 使用git checkout 来移动HEAD指针,移动的对象可以是分支指针也可以是快照。
  • HEAD指针可以指向快照也可以指向branch。当指向branch时提交后会和branch指针一起向后移动,当不指向branch提交时时则会在一个detached状态。
  • 当使用 git checkout < branch_name> 切换分支时,HEAD 会移动到指定分支。
git checkout <branch name>
  • 但是如果使用的是 git checkout ,即切换到指定的某一次提交,HEAD 就会处于 detached 状态(游离状态)
    • 利: 我们可以很方便地在历史版本之间互相切换,比如需要回到某次提交,直接 checkout 对应的 commit id 或者 tag 名即可。
    • 弊:在这个基础上的提交会新开一个匿名分支且提交是无法可见保存的,一旦切到别的分支,游离状态以后的提交就不可追溯了。
git checkout <commit id>

此时看

git branch
* (HEAD detached at 925fda6)  //此时head指向一个游离的状态
master

怎么解决?

  • 查看当前分支状态
git branch
* (HEAD detached at 925fda6)
master
  • 新建一个临时 tem 分支,把当前提交的代码放到整个分支
git branch tem
git checkout tem
  • 换回要回到的那个分支,这里是 master
git checkout master
  • 然后 merge 刚才创建的临时分支
git merge tem
Updating cad0be9..2437c6b
Fast-forward
......
  • 检查是否有冲突,没有就提交到远端
git push origin master
  • 删除临时分支
git branch -d tem

相对引用

^

引用名称^,表示让git寻找指定提交记录的父提交

如左图Git仓库中:

  • 当前有三个提交记录:C0,C1,C3
  • 当前只有一个main分支,而且main分支指向最近的一次提交记录C3
  • 也就是说HEAD—> main —>C3

在这里插入图片描述

接下来,我们执行命令git checkout main^,也就是说令HEAD切换到main的父节点

在这里插入图片描述

命令git checkout main^^,意思是令HEAD切换到main父节点的父节点
命令git checkout main^^^,意思是令HEAD切换到main父节点的父节点的父节点

我们也可以将HEAD作为相对引用的参照,如下图,指向命令:git checkout C3; git checkout HEAD^; GIT CHECKOUT HEAD^; git checkout HEAD^

在这里插入图片描述

~

如果我们要在提交树上走很多步的话,总不能敲^^^^^^^^^^,因此引入了~操作符

接下来我们看看效果

执行命令git checkout HEAD~4,后退4步

在这里插入图片描述

如左图所示, 当前分支位于bugFix上,因此状态为:HEAD–>bugFix—>C4

  • 执行命令git branch -f main HEAD~3
    • 上面命令的意思是将main分支强制指向HEAD的第3级提交

在这里插入图片描述

在这里插入图片描述

合并分支: git merge VS git rebase

如何理解git merge

不要用merge合并分支!!!!!!

实践

如下图所示,bugfix分支是从master分支分叉出来的。

在这里插入图片描述
我们需要合并 bugfix分支到master分支

fast-forward(快进)合并

如果master分支的状态没有被更改过

  • 因为bugFix分支的历史记录包含master分支所有的历史记录

  • 所以通过把master分支的位置移动到bugFix的最新分支上,git就会合并

  • 这样的合并被称为fast-forward(快进)合并。
    在这里插入图片描述

  • 执行合并时,如果设定了non fast-forward选项,即使在能够fast-forward合并的情况下也会生成新的提交并合并。

在这里插入图片描述

实践

  • 本来是在issue1上的,那么我们先切换master分支,然后把issue1分支导入到master分支。
  • 此时,master分支指向的提交移动到和issue1同样的位置。这个是fast-forward(快进)合并
$ git checkout master
$ git merge issue1

在这里插入图片描述

non fast-forward合并

如果master分支的历史记录有可能在bugfix分支分叉出去后有新的更新。

  • 这种情况下,要把master分支的修改内容和bugfix分支的修改内容汇合起来:
    在这里插入图片描述
  • 因此,合并两个修改会生成一个提交。
  • 这时,master分支的HEAD会移动到该提交上。
    在这里插入图片描述

实践

当前分支状态如下:

在这里插入图片描述
我们要合并issue3分支到master

$ git merge issue3
Auto-merging myfile.txt
CONFLICT (content): Merge conflict in myfile.txt
Automatic merge failed; fix conflicts and then commit the result.

自动合并失败。

  • 由于在myfile.txt同一行进行了修改,所以产生了冲突。

怎么办呢?

  • 查看myfile.txt中冲突的地方
$ cat myfile.txt 
first commit
add 把变更录入到索引中
<<<<<<< HEAD
commit 记录索引的状态
=======
pull 取得远端数据库的内容
>>>>>>> issue3

  • 修改掉冲突的地方
  • 重新提交
$ git add myfile.txt
$ git commit -m "合并issue3分支"

历史记录如下图所示。

  • 因为在这次合并中修改了冲突部分,所以会重新创建合并修改的提交记录。
  • 这样,master的HEAD就移动到这里了。
  • 这种合并不是fast-forward合并,而是non fast-forward合并。
    在这里插入图片描述

如何理解git rebase

理论

如下图所示,bugfix分支是从master分支分叉出来的:
在这里插入图片描述
如果使用rebase方法进行分支合并:

  • 首先,rebase bugFix分支到master分支,bugFix分支的历史记录会添加到master分支的后面
    在这里插入图片描述
  • 这时移动提交X和Y有可能会发生冲突,所以需要修改各自的提交时发生冲突的部分。
    在这里插入图片描述
  • rebase之后,master的HEAD位置不变。因此,要合并master分支和bugfix分支,即是将master的HEAD移动到bugfix的HEAD这里。
    在这里插入图片描述

实践

合并issue3分支的时候,使用rebase可以使提交的历史记录显得更简洁。

  • 现在暂时取消刚才的合并。
$ git reset --hard HEAD~

在这里插入图片描述

  • 切换到issue3分支后,对master执行rebase。
$ git checkout issue3
$ git rebase master
。。。。

When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To check out the original branch and stop rebasing run "git rebase --abort".
  • 合并失败。同样的,修改在myfile.txt发生冲突的部分
  • 提交不是使用commit命令,而是执行rebase命令指定 --continue选项
$ git add myfile.txt
$ git rebase --continue
Applying: 添加pull的说明

在这里插入图片描述

  • 这样,在master分支的issue3分支就可以fast-forward合并了。切换到master分支后执行合并
$ git checkout master
$ git merge issue3
  • myfile.txt的最终内容和merge是一样的,但是历史记录如下:
    在这里插入图片描述

删除分支

当分支已经开发完毕之后,就可以删除分支了

$ git branch -d issue1

错误:

不小心将所有更改提交到主分支

你可能正在开发一项新功能,由于太仓促,你忘记为它打开一个新的分支。这时候已经提交了大量文件,而且这些提交都位于主分支上。现在我们需要使用以下三个命令将所有这些更改回滚到新分支,注意:确保先提交或存储更改,否则一切都将丢失。

git branch feature-branch
git reset HEAD~ --hard
git checkout feature-branch

这将创建一个新分支,然后将主分支回滚到你进行更改之前的位置,然后最终检出你之前所有更改完整的新分支。

忘了将文件添加到最后一次提交

你可能错过了一个文件,忘了保存它,或者需要对最后一次提交做一个小改动。添加忘掉的文件,然后运行以下命令:

git add missed-file.txt
git commit --amend

此时,你可以修改提交消息,也可以只保存它以使其保持不变。

将错误的文件添加到仓库

但是如果你做的恰恰相反呢?如果你添加了一个不想提交的文件,该怎么办?如果你所做的只是暂存文件但尚未提交,那就像重置该暂存文件一样简单:

git reset /assets/img/misty-and-pepper.jpg

如果你已经提交了这些改变,那也不用担心,只需要在之前执行额外的步骤,如下:

git reset --soft HEAD~1
git reset /assets/img/misty-and-pepper.jpg
rm /assets/img/misty-and-pepper.jpg
git commit

上述命令将撤消提交,删除图像,然后在其位置添加新提交。

git回退到某个commit git回滚到某个提交

git是一个分布式版本控制软件,分布式版本库的做法使源代码的发布和交流都极为方便,因此有不少用户都在使用git。最近小编也正在学习git这款软件,发现要想熟练运用git,学会git中的一些命令是很重要的,如果我们要回滚到某个提交,就需要使用到回退命令,下面小编给大家具体来介绍一下。

git回退到某个commit

  • git reset --hard HEAD^ 回退到上个版本

  • git reset --hard HEAD~3 回退到前3次提交之前

  • git reset --hard commit_id 退到/进到 指定的commit

  • git push origin HEAD – force 强退至远程

git回退到某个commit 推送远程

1.先查询对应的提交历史,使用如下命令:

  • git log --pretty=oneline

2、版本回退,使用如下命令:

  • git reset --soft commitID //只删除commitID之后的提交记录log,代码的改动还在。

  • git reset --hard commitID //彻底删除commitID之后所做的改动,代码也一起回退回来了。(慎重用,用前最好备份一下代码,或者用git diff 生成一个patch)

3.把当前分支push到远程仓库并且让远程仓库和当前分支保持一致,使用如下命令(假定当前分支为master):

  • git push -f origin master

Git本次修改合并到上次提交

git commit --amend                #会通过core.editor指定的编辑器进行编辑

git commit --amend --no-edit      #不打开命令行,直接提交

Git log修改时间格式

我们经常会使用git log去查看提交记录,但是默认展示的提交时间是如下格式的:

Date: Thu Aug 29 19:15:05 2019 +0800

不太容易看懂,因此最好使用如下的命令,将提交时间格式化一下

git config --global log.date format:"%Y-%m-%d %H:%M:%S"

执行成功后,再执行 git log 命令,就可以看到格式良好的时间了。

Date: 2019-09-03 20:22:39

git 查看某个文件的修改记录

查看fileName相关的commit记录

  • git log filename

显示每次提交的diff

  • git log -p filename

查看某次提交中的某个文件变化,可以直接加上fileName

  • git show c5e69804bbd9725b5dece57f8cbece4a96b9f80b filename

git把某一次commit修改过的文件导出

使用git导出某次commit的文件

  • git diff-tree -r --no-commit-id --name-only f4710c4a32975904b00609f3145c709f31392140 | xargs tar -rf update_201800001.tar

使用git导出某次commit后的文件:

  • git diff f4710c4a32975904b00609f3145c709f31392140 HEAD --name-only | xargs tar -rf update_201800001.tar

git 导出新修改的文件

  • git archive -o update.zip HEAD $(git diff --name-only HEAD)

git提取出两次提交之间的差异文件并打包

  • git diff 608e120 4abe32e --name-only | xargs zip update.zip

远程分支

Git 拉取特定的远程分支

拉取特定的远程分支代码存在两种情形

  • 第一是本地没有项目,采用 git clone 链接名命令拉取的是远程 master 分支的代码,这个时候需要指定远程分支;
  • 第二是本地已有项目,但远程分支不存在对应的分支,这个时候也需要指定远程分支并创建本地分支。

1、git clone 指定远程分支

  • 不指定远程分支的情形下,默认拉取的是 master 分支的代码,指定分支的格式如下:
$ git clone -b dev https://gitee.com/xiaosheng/quartz.git
  • -b 表示选择分支,**dev **是分支名称,后面是仓库地址,这样就实现了远程分支的指定。

2、本地已有项目下拉取远程分支

  • 在本地已有项目的情形下,就不适宜采用 git clone 重新拉取一遍代码了,这个时候需要拉取远程分支并自动创建本地分支,命令如下:
$ git checkout -b developer_gen3_release origin/developer_gen3_release
  • dev 是本地分支, origin/dev 是远程分支,本地分支会自动与远程分支建立关联关系,执行 git branch -vv 命令查看本地分支与远程分支的对应关系。

其他:

// git checkout --track -b origin/daves_branch // 默认新建跟远端一样的分支
git checkout --track -b localBranchName origin/remoteBranchName  // 切换到远程分支并track

git删除远程分支

假设你已经通过远程分支做完所有的工作了——也就是说你和你的协作者已经完成了一个特性, 并且将其合并到了远程仓库的 master 分支(或任何其他稳定代码分支)。 可以运行带有 --delete 选项的 git push 命令来删除一个远程分支。 如果想要从服务器上删除 serverfix 分支,运行下面的命令:

$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
 - [deleted]         serverfix

基本上这个命令做的只是从服务器上移除这个指针。 Git 服务器通常会保留数据一段时间直到垃圾回收运行,所以如果不小心删除掉了,通常是很容易恢复的。

获取远程仓库的新分支以及删除远程仓库已删除的分支

需求

和同事合作开发一个项目。同事要新建一个分支,然后,我这边拉取这个分支即可。
然而同事新建分支并且推送到远程仓库之后,我这边通过git branch -a并不能看到这个分支。

解决办法

1、使用git fetch即可。这个命令的意思是

一旦远程主机的版本库有了更新(Git术语叫做commit),需要将这些更新取回本地,这时就要用到git fetch命令。

$ git fetch <远程主机名>

上面命令将某个远程主机的更新,全部取回本地。
git fetch命令通常用来查看其他人的进程,因为它取回的代码对你本地的开发代码没有影响。默认情况下,git fetch取回所有分支(branch)的更新。

2、除了取回新建的分支,怎么删除远程仓库已经删除的分支呢

运行如下命令即可:

git fetch -p // fetch 并删除不存在的远端跟踪分支(prune)

本地分支与远程分支关联与解除关联

查看本地分支与远程分支的映射关系

  • git branch -vv
    • 如果本地分支没有和远程分支建立关系,那么就无法进行推拉操作

建立当前分支与远程分支的映射关系:

  • 如果本地新建了一个分支 branch_name,但是在远程没有
    • git push --set-upstream origin feature/add_order (将本地分支与远程分支关联 ,远程也会新建一个分支 feature/add_order)
  • ​​​​​​​如果远程有一个分支feature/add_order,需要将本地分支feature/add_order与远程分支feature/add_order关联起来
    • git branch -u origin/feature/add_order

​​​​​​​​​ 撤销本地分支与远程分支的映射关系

  • git branch --unset-upstream

您尚未完成合并(MERGE_HEAD存在)

push代码的时候,别人已经更新代码

error: 您尚未结束您的合并(存在 MERGE_HEAD)。
提示:请在合并前先提交您的修改。
fatal: 因为存在未完成的合并而退出。
1.error: 您尚未结束您的合并(存在 MERGE_HEAD)。
2.提示:请在合并前先提交您的修改。
3.fatal: 因为存在未完成的合并而退出。

解决办法

  • git merge --abort
  • git reset --merge

git如何取消merge

  • 当我们使用git merge操作合并代码但还没add时,若想取消这次合并,使用 git merge --abort 命令即可
  • 假如不幸已经 git add 了怎么办呢? 其实也很简单,先用 git reflog 指令显示历史的操作,再用 git reset --hard commit id 就可以回退到操作之前的状态了。

总结:分支的作用

  • 分支是为了将修改记录的整体流程分叉保存。
  • 分叉后的分支不受其他分支的影响,所以在同一个仓库中可以同时进行多个修改

在这里插入图片描述

  • 为了不受其他开发人员的影响,在主分支上建立自己专用的分支。
  • 完成工作后,将自己分支上的修改合并到主分支。
  • 因为每一次提交的历史记录都会被保存,所以当发生问题时,定位和修改造成问题的提交就容易多了
    在这里插入图片描述
  • 23
    点赞
  • 130
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值