git 代码没了,git rebase 合并提交记录,git stash

35 篇文章 2 订阅

问题

lhf-dev没有 add 切换到dev,pull,导致 lhf-Dev git status 也没有没有add之前的代码了。
切换到lhf-dev,ctrl+z undo reload from disk
就找回了

git合并提交记录

参考多个提交记录合并成一个提交记录

在使用git进行版本管理的过程中,开发人员代码的提交可能需要在多个分支之间进行切换,每个开发人员提交代码的习惯也是不一样的,有的喜欢开发完成提交,有个喜欢半个小时提交一次……有些时候我们并不希望在另一个分支上看到当前分支的多次提交记录,只希望将多个提交记录合并成一个记录,达到美化commit history的效果

创建提交记录

首先在分支上创建了3个提交记录,如下图:
在这里插入图片描述

合并提交记录

假设需要合并这3个提交记录,执行命令

git rebase -i HEAD~3

会有如下提示:
在这里插入图片描述

pick是rebase时的指令,具体我们还可以使用如下指令:

选择pick指令,git会应用这个提交,以同样的提交信息(commit message)保存提交
选择reword指令,git会应用这个提交,但需要重新编辑提交信息
选择edit指令,git会应用这个提交,但会因为amending而终止
** 选择squash指令,git会应用这个提交,但会与上一次的提交合并
选择fixup指令,git会应用这个提交,但会丢掉提交日志
选择exec指令,git会在shell中运行这个命令

如果合并成功会打开另外一个文件文件,在这里我们输入这次合并时的提交记录信息。

如果合并有冲突,在解决冲突后需要输入

git add .
git rebase --continue

如果不想合并了,放弃合并的指令是

git rebase --abort

接下来,如果我们修改提示文件:

pick 3e60dd4 创建合并提交记录
s 627c7d7 修改合并提交记录 		  表示合并到3e60dd4版本
s 3a259d9 完成合并提交记录   	      表示合并到627c7d7版本

在这里插入图片描述
如果我们不想修改任何信息,保存即可,也可以修改最终的提交信息后再保存。

# This is a combination of 3 commits.
# This is the 1st commit message:

合并提交记录完成

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.

然后我们再看下这时的git history

* 44c536b - (HEAD -> feature) 合并提交记录完成 (4 minutes ago) <Blackfat>

可以看到3条提交记录,已经合并成了一条记录,并且修改了最终的提交信息。

rebase有冲突

$ git rebase -i HEAD~2

Auto-merging 冲突文件
CONFLICT (content): Merge conflict in 冲突文件
error: could not apply 版本id... 版本提交名

Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".

Could not apply 版本id... 版本提交名

上面意思就是 首先处理冲突,然后 git add . ,然后 git rebase --continue
或者跳过合并 git rebase --skip
或者终止合并 git rebase --abort

查看一下status

$ git status
interactive rebase in progress; onto 版本id
Last commands done (2 commands done):
   pick 版本id 版本提交名
   s 版本id 版本提交名
No commands remaining.

提示我现在有正在合并的操作

You are currently rebasing branch 'dev' on '版本id'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

        both modified:  冲突文件

no changes added to commit (use "git add" and/or "git commit -a")

上面意思就是说 解决之后如果没有其他操作需要commit,就 git add 或者 git commit -a

如果直接 git rebase --continue 就还是提示让 git add .

$ git rebase --continue
冲突文件: needs merge
You must edit all merge conflicts and then
mark them as resolved using git add

$ git add .
$ git rebase --continue
[detached HEAD 版本id] vim编辑rebase的提交名
 Date: Tue Oct 26 17:42:17 2021 +0800
 2 files changed, 25 insertions(+), 13 deletions(-)
Successfully rebased and updated refs/heads/dev.

总结:首先处理冲突,然后 git add . ,然后 git rebase --continue

合并后的本地路径提交到远程

合并完本地记录后

git push -f

这条指令将本地仓库合并记录推送支远端仓库,如果没有-f的话,系统会提示你,当前记录不是最新的,无法提交, -f 是force的意思,强制提交。

其中的参数

pick

pick只是意味着包括提交。重新进行命令时,重新安排pick命令的顺序会更改提交的顺序。如果选择不包括提交,则应删除整行

只要不动pick的 顺序,就代表什么都不做

改变提交 5.txt 和 4.txt 的顺序
pick 8b485bb add 4
pick a75ed74 add 5

vi编辑器,首先Esc ,进入命令模式,移动到第一行 按dd,本行就被剪切,pick a75ed74 add 5就变成了第一行,接着按 p刚刚剪切的就成了第二行,快速交换顺序
更改为

pick a75ed74 add 5
pick 8b485bb add 4

接着 Esc,:wq 保存退出

git log查看,4 和 5 的顺序改变了

在这里插入图片描述

删除某一个提交
pick 8b485bb add 4
pick a75ed74 add 5

更改为

pick 8b485bb add 4

接着 Esc,:wq 保存退出

reword

该reword命令与相似pick,但是使用后,重新设置过程将暂停并为您提供更改提交消息的机会。提交所做的任何内容更改均不受影响,只是更改了提交名字

修改提交信息
pick 9cd34c4 add 2
pick 63ce9fb add 3
pick 575fd8b add 5

改为

r 9cd34c4 add 2				修改 9cd34c4 的提交信息
pick 63ce9fb add 3
pick 575fd8b add 5

接着 Esc,:wq 保存退出

git会说 开始执行,接着弹出一个编辑窗口

add 2    修改这里即可

# Please enter the commit message for your changes. Lines starting
......

edit

如果您选择edit提交,则将有机会修改提交,这意味着您可以完全添加或更改提交。您还可以进行更多提交,然后再继续进行变基。这使您可以将大型提交拆分为较小的提交,或者删除在提交中所做的错误更改。

两个提交之间 再加提交

我们要在 add 3 和 add 5 之间 添加一条提交

git rebase -i HEAD~2

pick 6934312 add 3
pick 5ce6dde add 5

# Rebase 7f9d45d..5ce6dde onto 7f9d45d (2 command(s))
# ....

改为

e 6934312 add 3
pick 5ce6dde add 5

可以看到,我们的master分支多了REBASE-i 1/2

$ git rebase -i HEAD~2
Stopped at 6934312135c150bf74bead26e371df1443273ca4... add 3
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue

---------------这里--------------
xxxxxx MINGW32 ~/Desktop/git-demo (master|REBASE-i 1/2)

尝试做一些修改,给3.txt 增加一些内容,然后提交

git add 3.txt

git commit -m "edit 3.txt"
[detached HEAD 7262a57] edit 3.txt
 1 file changed, 1 insertion(+)

恢复rebase

git rebase --continue
Successfully rebased and updated refs/heads/master.

git log 查看,在 add 5 和 add 3 中间 增加了我们刚刚的修改
在这里插入图片描述

想要单纯的修改这次提交内容和消息

参照上面的做到这一步,我们选择提交的方式 加一个参数 git commit --amend修改

git add 3.txt

git commit --amend

# 这样 就不会在多出一次提交
# 本次对 3.txt的修改会记录 到  add 3  这次提交记录中

接着结束这次 rebase

git rebase --continue
Successfully rebased and updated refs/heads/master.

squash

该命令使您可以将两个或多个提交合并为一个提交。提交被压缩到其上方的提交中。Git使您有机会编写描述这两个更改的新提交消息。

参考上面git合并提交记录

fixup

这类似于squash,但是要合并的提交已丢弃其消息。提交仅合并到其上方的提交中,并且较早提交的消息用于描述这两个更改。

git rebase -i HEAD~2


pick 7f9d45d add 2 ~ new comment
pick 311adc9 add 3

# Rebase 77bd0eb..311adc9 onto 77bd0eb (2 command(s))
#  ----------------------
# 变更为
# -----------------------

pick 7f9d45d add 2 ~ new comment
f 311adc9 add 3

# 保存

exec

这使您可以对提交运行任意的Shell命令。

git rebase -i HEAD~3


# 弹出编辑框
#----------------------------
pick 81fe4d0 添加test2.txt和test3.txt
pick 77bd0eb add 1
pick e7c68b8 add 2 ~ new comment

# Rebase 258a059..e7c68b8 onto 258a059 (3 command(s))
#....

# ----------------
# 加一行 命令
# ---------------
x echo "Hello is echo do ......."
pick 81fe4d0 添加test2.txt和test3.txt
pick 77bd0eb add 1
pick e7c68b8 add 2 ~ new comment


## 执行了我们刚刚键入的命令
Executing: echo "Hello is echo do ......."
Hello is echo do .......
Successfully rebased and updated refs/heads/master.

git rebase -i HEAD~3 最后的数字写错了

或者 git rebase后怎么恢复 / 撤销rebase / rebase 报冲突了

如果 git rebase -i HEAD~3 发现最后的数字写错了,可以不修改前面的pick,就会正常提交
保持 每个提交记录的  pick   cdsada3n32q 
然后退出编辑模式后,放弃合并  git rebase --abort

如果想要放弃当前rebase操作,用 git rebase --abort
如果冲突已经解决,先add冲突文件,即  git add filename  之后, git rebase --continue

git stash

一、git pull 拉代码的时候,或者切换分支的时候,防止冲突和不便,,会用到git stash,将工作区内容暂存起来。

比如:为了fix 一个bug, 先stash, 使返回到自己上一个commit, 改完bug之后再stash pop, 继续原来的工作。怎么办:

git stash会把所有未提交的修改(包括暂存的和非暂存的)都保存起来,stash是本地的,不会通过git push命令上传到git server上

git stash 	备份当前工作区的内容,保存到git 栈中,从最近的一次commit中读取相关内容
git pull		  或者做其他的工作    
git stash pop 	从git栈中获取到最近一次stash进去的内容,恢复工作区的内容。。获取之后,会删除栈中对应的stash。。
git stash save message   自定义保存message

由于可能会stash多次,git使用栈管理,我们可以使用git stash list查看所有的stash
git stash list		显示git栈中的所有工作区内容的备份

git stash apply stash@{1},就可以把版本号为stash@{1}的备份取出,不会删除对应的stash。。0为最新版本

git stash clear 	清空git栈,删除所有缓存的stash

获取stash
git stash pop 是弹出栈顶的一个 stash ,也就是最后一次存储的 stash,在存储多个stash ,想取出非栈顶的一个的情况下,是不适用的。这个时候要使用:

git stash list //查看暂存区的所有暂存修改
git stash apply stash@{X} //取出相应的暂存	

报错 unknown option: -encodedCommand 则   -------->    git stash apply "stash@{X}"
	
git stash drop stash@{X} //将记录列表中取出的对应暂存记录删除

如果得到这结果说明你的stash 是没有东西的
在这里插入图片描述

移除某一个stash

$ git stash list
stash@{0}: WIP on master: 049d078 added the index file

$ git stash drop stash@{0}
Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43)


$ git stash drop stash@{0} 这是删除第一个队列
报错的话就
$ git stash drop 0 这个即可

git stash 不会缓存,在工作目录中新的文件(untracked files)、被忽略的文件(ignored files)

还可以git reset --hard放弃本地修改,然后就可以git pull了。。但是不推荐使用git reset --hard指令,实在是太危险啦!

二、但是git stash pop取出备份的时候也会出现冲突

比如,有个文件login.java,,你修改了一段代码,git stash保存以后,你从服务器上继续git pull了别人的代码

如果此时,别人的代码也修改了login.java。。。

此时当我们使用git stash pop 的时候,就会发生冲突,因为我们的修改不是基于最新的pull下来的文件的基础上。。所以git很难判断,

解决方法:

备份我们修改后的文件,,删除程序文件中我们所做的修改,重新pull,,然后在用我们备份好的文件替换掉,,再push上去即可。。

另一种就是上面说的git reset --hard了,,,,直接忽略本地的修改。。。但这样明显太危险!

实例

此时我在 feature_666 分支,非常聚精会神加持高专注地实现一个功能 666 模块,简直键盘如飞的编写代码~~~
然后这时,客户反馈出一个 bug , 非常严重,必须立马解决,优先级为 0 !!!
于是,我需要去到 release 分支去 checkout 新的分支去工作了,但是 666 功能还没完成怎么办?

此时我面临着一个选择题:
A:提交后切换,代码保存到分支 feature_666,却产生一个无意义的提交
B:不提交直接切换,然而这个选项根本没人会选。

是不是很难选,此时,别忘记还有 C 选项!

C:使用 git stash , 将当前修改(未提交的代码)存入缓存区,切换分支修改 bug ,回来再通过 git stash pop 取出来。

================================================================

bug出现

上一个 commit 的时候,代码快照是这个样子的

public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        String s = "大家好,我是段小憨";
 
    }
}

此时的我在写代码如下:

public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        String s = "大家好,我是段小憨";
        String s1 = "我现在在写一个超级厉害的功能,但是我还没写完,甚至还有点地方在报错";
 
    }
}

代码到此处,紧急 bug 出现了,一秒都不能等, 选择下列操作

git stash //将修改存储到暂存区,工作区会删除相对于上一个提交版本的修改
git checkout <bug_branch>

在这里插入图片描述
暂存后的工作区代码会恢复到最后一次提交时的代码:

public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        String s = "大家好,我是段小憨";
 
    }
}

查看修改

如果你有丢失代码的经历,肯定会对这个之前没接触的新命令不放心,那么怎么确定你操作成功了呢?

git stash  show  //查看刚才暂存的修改

在这里插入图片描述

继续开发

现在 bug 改完了,要重新回来开发了,取出修改

git checkout <feture_branch> //切换刚才功能开发的分支
git stash pop //取出修改

在这里插入图片描述
取出修改后的工作区代码为:

public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        String s = "大家好,我是段小憨";
        String s1 = "我现在在写一个超级厉害的功能,但是我还没写完,甚至还有点地方在报错";
 
    }
}

git stash深入一点

修改存储到什么位置了?

当我们使用 git init给项目添加版本控制的时候,会在项目路径下生成一个 .git 隐藏文件夹。.git 中存储着版本管理的所有信息。
.git/refs/stash 中,存储的是最后一个 stash 对应的节点指针
在这里插入图片描述
同样,在 .git/log/refs/stash 中可以看到我们全部的 stash 记录信息

我们来尝试一下修改文件,然后再次使用 git stash ,此时我们有个两个 暂存修改,那么怎么查看呢?

git stash list //查看暂存区的所有暂存修改记录

在这里插入图片描述
此时你有没有发现,这两个的名称是一样,这是个什么鬼?
别怕,名称是一样的,但是指向的修改是不一样的,我们从.git/log/refs/stash 中可以看到 两者的对应的节点指针是不一样的

stash 的存储的名称是怎么来的,可以修改吗?

当使用git stash 创建 stash 的时候,会给 stash 一个默认的名称。之前有说,stash 存储的内容就是,当前工作区距当前分支最后一次提交时的修改。所以,stash 的默认命名规则就是:

WIP on <branch_name><latest_commit_id> <latest_commit_message>

WIP,Work In Progess的简称,说明代表了工作区进度。
同样的还有 Index ,代表的是已经被 add 但是还未被提交的进度。

如果在未提交的情况下,执行 git stash 两次,就如上图,无法准确分辨两个stash 具体修改的是哪些内容,这样用,显的伟大的 Git 一点都不智能,怎么可以!。

所以,在这种情况下,给 stash 存储的修改起个名字,显然非常重要,方式如下:

git stash save <message>
$ git stash save "test-cmd-stash"
Saved working directory and index state On autoswitch: test-cmd-stash
HEAD 现在位于 296e8d4 remove unnecessary postion reset in onResume function
$ git stash list
stash@{0}: On autoswitch: test-cmd-stash

从stash创建分支

如果你储藏了一些工作,暂时不去理会,然后继续在你储藏工作的分支上工作,你在重新应用工作时可能会碰到一些问题。如果尝试应用的变更是针对一个你那之后修改过的文件,你会碰到一个归并冲突并且必须去化解它。如果你想用更方便的方法来重新检验你储藏的变更,你可以运行 git stash branch,这会创建一个新的分支,检出你储藏工作时的所处的提交,重新应用你的工作,如果成功,将会丢弃储藏。

$ git stash branch testchanges
Switched to a new branch "testchanges"
# On branch testchanges
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#      modified:   index.html
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#
#      modified:   lib/simplegit.rb
#
Dropped refs/stash@{0} (f0dfc4d5dc332d1cee34a634182e168c4efc3359)

注意

新增的文件,直接执行stash是不会被存储的
在这里插入图片描述
如上图:在git status 那一步很明显可以看出来,我修改了README,添加了新文件abc.txt,然后执行了git stash save后,在执行git stash list 可以看到刚才的save是的信息,然后使用git stash show ,只显示了README的改动被存起来了

执行了git statsh 以后,被存起来的在当前目录再执行git status 就看不到了,但是我们现在再执行git status
在这里插入图片描述
这个文件还在,说明没有被存起来。说白了就是没有在git 版本控制中的文件,是不能被git stash 存起来的

那要怎么办呢,这个文件我也想存起来,很明显,先执行下git add 加到git版本控制中,然后再git stash就可以了
在这里插入图片描述
最后一步可以看出来,这个新增文件已经被stash了。

这个时候再执行下git status ,被存起来的在当前目录就看不到了,如下:
在这里插入图片描述

这个时候,想切分支就再也不会报错有改动未提交了。

如果要应用这些stash,直接使用git stash apply或者git stash pop就可以再次导出来了。

总结下:git add 只是把文件加到git 版本控制里,并不等于就被stash起来了,git add和git stash 没有必然的关系,但是执行git stash 能正确存储的前提是文件必须在git 版本控制中才行。

常规 git stash 的一个限制是它会一下暂存所有的文件。有时,只备份某些文件更为方便,让另外一些与代码库保持一致。一个非常有用的技巧,用来备份部分文件:

1. add 那些你不想备份的文件(例如: git add file1.js, file2.js)
2. 调用 git stash –keep-index。只会备份那些没有被add的文件。
3. 调用 git reset 取消已经add的文件的备份,继续自己的工作。
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值