赞
踩
lhf-dev没有 add 切换到dev,pull,导致 lhf-Dev git status 也没有没有add之前的代码了。
切换到lhf-dev,ctrl+z undo reload from disk
就找回了
在使用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条提交记录,已经合并成了一条记录,并且修改了最终的提交信息。
$ 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 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命令与相似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提交,则将有机会修改提交,这意味着您可以完全添加或更改提交。您还可以进行更多提交,然后再继续进行变基。这使您可以将大型提交拆分为较小的提交,或者删除在提交中所做的错误更改。
我们要在 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.
该命令使您可以将两个或多个提交合并为一个提交。提交被压缩到其上方的提交中。Git使您有机会编写描述这两个更改的新提交消息。
参考上面git合并提交记录
这类似于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
# 保存
这使您可以对提交运行任意的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后怎么恢复 / 撤销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 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 取出来。
================================================================
上一个 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 init给项目添加版本控制的时候,会在项目路径下生成一个 .git 隐藏文件夹。.git 中存储着版本管理的所有信息。
.git/refs/stash 中,存储的是最后一个 stash 对应的节点指针
同样,在 .git/log/refs/stash 中可以看到我们全部的 stash 记录信息
我们来尝试一下修改文件,然后再次使用 git stash ,此时我们有个两个 暂存修改,那么怎么查看呢?
git stash list //查看暂存区的所有暂存修改记录
此时你有没有发现,这两个的名称是一样,这是个什么鬼?
别怕,名称是一样的,但是指向的修改是不一样的,我们从.git/log/refs/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
如果你储藏了一些工作,暂时不去理会,然后继续在你储藏工作的分支上工作,你在重新应用工作时可能会碰到一些问题。如果尝试应用的变更是针对一个你那之后修改过的文件,你会碰到一个归并冲突并且必须去化解它。如果你想用更方便的方法来重新检验你储藏的变更,你可以运行 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的文件的备份,继续自己的工作。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。