使用Git常用操作命令

一、Git配置

1.1 生成ssh密钥绑定GitHub账号

# 输入命令生成密钥对,替换成自己邮箱,然后一路回车
ssh-keygen -t rsa -C "youremail@example.com"

# 将生成的公钥打印出来复制,将这串文本复制粘贴到GitHub的Setting->SSH and GPG keys中
cat ~/.ssh/id_rsa.pub

# 输入命令检查是否绑定成功,输入yes后,如果出现Hi,xxx!则绑定成功
ssh -T git@github.com

#如果配置以后报错:Permission denied (publickey) 
#则在 ~/.ssh/config 文件中加入一下内容:
Host *
PubkeyAcceptedKeyTypes +ssh-rsa

1.2 配置用户名和邮箱信息

Git 提供了一个叫做 git config 的工具,专门用来配置或读取相应的工作环境变量,配置方式有以下三种:

# 查看配置信息,一开始为空
git config --list

# 修改 /etc/gitconfig 文件,对所有用户的所有代码库都生效,很少配置这个

# 修改 ~/.gitconfig 文件,对所有代码库生效,一般都配置这个
git config --global user.name "你的名字"
git config --global user.email "你的邮箱"

# 修改 .git/config 文件,只对当前的代码库有效
git config --local user.name "你的名字"
git config --local user.email "你的邮箱"

# 配置后,远程仓库提交的commit里对应的用户即为 user.name

1.3 Git 命令无法Tab补全问题

# 查询git版本号
git version
# 下载版本号对应的git-completion.bash文件,如2.40.0就是这样
wget https://raw.githubusercontent.com/git/git/v2.40.0/contrib/completion/git-completion.bash
# 最好是将其作为隐藏文件放在~/路径下
mv git-completion.bash ~/.git-complition.bash
# 在.bash_profile文件末尾加上,其中.代表source命令
if [ -f ~/.git-completion.bash ]; then
    . ~/.git-completion.bash
fi
# 执行~/.bash_profile文件中的命令,如果不起作用,就把.bash_profile中的~换成绝对路径
source ~/.bash_profile

二、基本操作

2.1 创建仓库

一份本地代码,可能会用到两个或者更多的远程仓库地址。比如有一个上游社区的项目,仓库在gitlab上,我在我自己的帐号上fork了一份,并将其clone到了本地。如果上游项目更新过,fork的项目不会同步的,我需要在本地pull上游社区的内容,此时就需要我将社区的仓库地址add到本地。

# 可参考“5.1 提交代码至GitHup”
git init	#在目录中创建新的 Git 仓库,ls .git/可查看仓库信息,所有有关项目的快照数据都存放在其中。

git remote add [shortname] [url]	#添加远程版本库的地址,shortname为远程地址的别名
git remote rename oldname newname	#修改现有远程地址的别名
git remote show [shortname]			#显示别名对应仓库的信息
git remote rm name					#根据别名,删除现有远程仓库

git clone [url]	#拷贝一个 Git 仓库到本地,让自己能够查看该项目,或者进行修改。
git clone --branch br_name --depth 1 [url]	#只拉取指定分支到本地仓库

2.2 提交代码

git add [file1] [file2] ...		#将工作区文件或目录提交到暂存区。
# 只提交一个文件中的部分修改代码:
# git 中用"hunk"来表示一个文件中邻近区域中的代码修改块,
# 比如用git diff 查看修改时,两个@@符号分割的一个区域就是一个hunk。
git add [-p|--patch] [file1]
# 执行该命令就会进入交互式的操作界面:
	y - 将当前的hunk进行提交
	n - 不提交当前hunk,进入下一个hunk
	q - 退出交互式界面,不提交当前hunk以及后面的所有hunk
	a - 提交当前hunk以及后面的所有hunk,并退出界面
	d - 不提交当前hunk以及后面的所有hunk,效果与q一样,也会退出交互式界面
	g - 选择一个hunk并跳转过去,输入后会列出所有hunk的编号,输入编号就跳转到对应的hunk
	/ - 输入一个正则表达式,选择一个包含搜索词的hunk进行跳转
	j - 暂时不确定是否保存当前hunk,跳转到下一个没确定的hunk
	J - 暂时不确定是否保存当前hunk,跳转到下一个hunk
	k - 暂时不确定是否保存当前hunk,跳转到上一个没确定的hunk
	K - 暂时不确定是否保存当前hunk,跳转到上一个hunk
	e - 手动修改hunk块的内容,将`-` 开头的行替换为 ` `则不会删去这行,删除`+`为首的行则不提交这个新增,以`#`开始的行会被忽略
	? - 显示帮助信息

git commit [file1] [file2] ... -m [message]	#给暂存区域生成快照并提交至本地仓库,[message] 是一些备注信息。
git commit -a	#-a参数设置修改文件后不需要执行 git add 命令,直接提交至本地仓库。
git commit --amend [file1] ...	#使用一次新的commit,替代上一次commit,提交至远程仓库也可以修改。

# 从将本地的分支版本上传到远程并合并
# PS:分支推送顺序的写法是<来源地>:<目的地>,所以git pull是<远程分支>:<本地分支>,git push是<本地分支>:<远程分支>
git push <远程主机名> <本地分支名>:<远程分支名> [--force]
git push origin HEAD:refs/for/br_name	#将当前分支的最新以此commit推送到远程主机origin上的对应的br_name分支上。
	--force #强制推送,会使用本地分支的commit覆盖远端push分支的commit。
			#即,如果其他人在相同的分支push了新的commit,这一举动将“删除”他的那些commit!
			#就算在强制push之前先fetch并且merge或rebase也是不安全的,
			#因为这些操作到push之间依然存在时间差,别人的commit可能发生在这个时间差之内。
			#如果push的commit不是首次push,也就是之前push后又修改了一些东西再push,一般用该参数
	--force-with-lease	#强制推送,但将解决force存在的安全问题,如果远端有其他人推送了新的提交,那么推送将被拒绝。
						#被拒绝时,需要fetch 仓库,然后确认其他人是否对此分支有新的修改,没有则可继续推送。

2.3 更新代码

更新代码时可能会有冲突,可以使用git stash命令将本地工作区备分,放入git栈中,工作区内容恢复到仓库head最后一次提交的内容。然后git pull / git fetch + git merge更新或合并代码,最后再git stash pop命令恢复备份到工作区,如过有冲突,需要解决冲突再git stash pop

# PS:注意,分支推送顺序的写法是<来源地>:<目的地>,所以git pull是<远程分支>:<本地分支>,而git push是<本地分支>:<远程分支>
git pull <远程主机名> <远程分支名>:<本地分支名>	#更新远程仓库中的代码到本地工作区间
git pull origin master				#将远程主机 origin 的 master 分支拉取过来,与本地当前分支合并
git pull origin master:brantest		#将远程主机 origin 的 master 分支拉取过来,与本地的 brantest 分支合并
git pull origin tag_name			#将远程主机 origin 的 tag_name标签拉取过来,与本地当前分支合并

git pull --rebase origin master:brantest
	#当有多个人在master分支上开发的时候,当别人push新的commit上去,而你本地的commit还没有push
	#在你push之前要先pull代码,此时就要加参数--rebase,从而实现变基操作,效果如下图
	     ---E---> other
	    |	| push
	A---B---E---> master
	    |
	     ---C---D--->brantest
	    # git pull --rebase master
	     ---E--->other
	    |	| push
	A---B---E---> master
		    |
		     ---C---D
     
git pull = git fetch + git merge
git fetch <远程主机名> <分支名>	#将远程主机的最新内容拉到本地仓库
git merge [branch]				#合并指定分支到当前分支

# eg:
# 从远程仓库更新代码,到本地仓库
[loongson@bogon luajit]$ git fetch origin larch64
来自 ssh://rd.loongson.cn:29418/luajit
 * branch            larch64    -> FETCH_HEAD
[loongson@bogon luajit]$ git merge FETCH_HEAD	#FETCH_HEAD是git自己创建的临时分支
更新 bbb6188..644fafd
Fast-forward
 src/lib_jit.c            | 2 +-
 src/lj_asm_loongarch64.h | 6 +++---
 src/lj_jit.h             | 6 +++---
 src/vm_loongarch64.dasc  | 5 +++++
 4 files changed, 12 insertions(+), 7 deletions(-)

 # 或者使用以下方式:
 git fetch origin larch64:temp #temp是本地在创建一个临时分支
 git diff temp #查看从远程拉下来的分支和当前所在分支的异同,如果有冲突要修改
 git merge temp #合并temp分支到当前分支
 git branch -d temp #删除临时分支

2.4 代码回退

checkout命令用于从历史提交(或者暂存区域)中拷贝文件到工作目录,也可用于切换分支。

git checkout -b 本地分支名 origin/远程分支名	#将远程git仓库里的指定分支拉取到本地(本地不存在的分支)
git checkout [--p|--patch] <files>	#暂存区 -> 工作区间,工作区间修改,单位git add

reset命令把当前 HEAD 和 branch 指向另一个位置,并且有选择的变动工作目录和索引。也用来在从历史仓库中复制文件到索引,而不动工作目录。

git reset [--soft | --hard | --mixed] [HEAD]
--hard	#重置位置的同时,直接将working Tree工作目录、index暂存区及repository都重置成目标Reset节点的內容
		#所以效果看起来等同于清空暂存区和工作区
--soft	#重置位置的同时,保留working Tree工作目录和index暂存区的内容,只让repository中的内容和reset目标节点保持一致
		#因此原节点和reset节点之间的【差异变更集】会放入index暂存区中(Stagedfiles)
		#所以效果看起来就是工作目录的内容不变,暂存区原有的内容也不变,只是原节点和Reset节点之间的所有差异都会放到暂存区中
--mixed(默认)
		#重置位置的同时,只保留Working Tree工作目录的內容,但会将Index暂存区和Repository中的內容更改和reset目标节点一致
		#因此原节点和Reset节点之间的【差异变更集】会放入Working Tree工作目录中
		#所以效果看起来就是原节点和Reset节点之间的所有差异都会放到工作目录中

HEAD		#最新提交
HEAD^		#上一个提交版本
HEAD^^		#上上一个提交版本
HEAD~3		#上上上一个提交版本,往上3个版本

# eg:
git reset HEAD file				#本地仓库 -> 暂存区,工作区中修改了文件且git add到暂存区,但是尚未commit
git reset --hard HEAD^			#回退工作区中的文件到上一个commit版本,也就是HEAD指针指向上一次commit
git reset --hard commit_id		#回退工作区的文件到指定commit_id,也就是HEAD指针指向commit_id

2.5 删除代码

git clean 从你的工作目录中删除所有没有 tracked,没有被管理过的文件。

#---git rm---#
git rm [-r] <file>       #将文件从暂存区和工作区中删除,-r递归删除
git rm -f <file>	    #如果删除之前修改过并且已经放到暂存区域的话,则必须要用强制删除选项 -f
git rm --cached <file>  #只从暂存区删除,保留工作区
#---------------#

#---git clean---#
git clean -n #是一次 clean 的演习, 告诉你哪些文件会被删除,不会真的删除

git clean -f <path>     #删除指定路径下的没有被 track 过的文件
git clean -f            #删除当前目录下所有没有 track 过的文件
git clean -df           #删除当前目录下没有被 track 过的文件和文件夹,-d递归删除
    #不会删除 .gitignore 文件里面指定的文件夹和文件, 不管这些文件有没有被 track 过

git clean -xf			#删除当前目录下所有没有 track 过的文件
    #不管是否是 .gitignore 文件里面指定的文件夹和文件
#---------------#

n :显示将要被删除的文件
d :递归删除
f :强制运行
x :也删除忽略的文件
X :只删除忽略的文件

三、查看变化信息

3.1 查看提交历史信息

不熟悉查看历史提交记录可阅读Git 查看提交历史

git log [<options>] [<file>]	#查看历史提交记录。
	--stat					#显示commit历史,以及每次commit发生变更的文件
	--pretty=oneline 		#选项来查看历史记录的简洁的版本
	-5 --pretty --oneline	#显示过去5次的提交记录
	--graph					#命令可以看到分支合并图
	--author=<pattern>		#查找指定坐着的提交记录
	-S [keyword]			#根据关键字搜索提交历史
	-p						#显示每个文件修改的内容

#查看历史提交的分支合并图,合并是加上--no-ff参数
git log --graph --pretty=oneline
#	*   98a2387 (HEAD -> master) merge with no-ff
#	|\  
#	| * be0b788 (dev) add merge
#	|/  
#	* 598ea11 & simple
#	* 0df82bb branch test
#	* 85f02d0 add test.txt

git blame <file>	#以列表形式查看指定文件每一行代码的历史修改记录。

git reflog	#记录了每一次git的命令,

3.2 查看修改内容

git status	#查看文件、目录在工作区间和暂存区中的状态。

git diff	#命令用于比较工作区和缓存区的区别。
git diff --staged	#比较的缓存区和本地仓库的区别。
git diff <commit>	#查看工作目录同本地仓库指定commit的内容的差异,<commit>=HEAD时:查看工作目录同最近一次commit的内容的差异。
git diff <commit> <commit>	#本地仓库任意两次commit之间的区别。

git show <commit>			#查看commit信息及修改的所有内容
git show <commit> --stat	#查看commit信息及修改的所有文件
git diff <commit> --stat	#只查看commit修改的所有文件

3.3 查看仓库位置/历史命令

git remote -v				#查看当前本地仓库与哪些远程仓库连接
git remote show [remote]	#显示某个远程仓库的信息

# 该命令可以在“2.4 代码回退”中使用
# 如果不小心回退了最新的commit,可以通过这个命令找到commit_id,从而再次让HEAD指向commit_id
git reflog	#记录了每一次git的命令

四、分支和标签

4.1 查看/新建/切换/合并/删除/更新分支

软件开发中,总有无穷无尽的新的功能要不断添加进来。添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个功能分支,在上面开发,完成后合并,最后再删除该功能分支。

#=== 查看分支 ===#
git branch		#列出所有本地分支。
git branch -r	#列出所有远程分支。
git branch -a	#列出所有本地分支和远程分支
git branch --contains commit_id/tag_name [--all]	# 查看某个commit/tag属于哪个分支
# 查看远程分支的创建日期
git for-each-ref --sort=committerdate refs/remotes/origin/ --format='%(committerdate:short) %(refname:short)'
# 查看特定远程分支的创建日期
git for-each-ref --sort=committerdate refs/remotes/origin/branch1 --format='%(committerdate:short) %(refname:short)'

#=== 新建分支 ===#
git branch [branch-name]		#新建一个分支,但是依旧停留在当前分支
git checkout -b [branch]		#新建一个分支,并切换到该分支
git branch [branch] [commit]	#新建一个分支,指向指定commit
git branch --track [branch] [remote-branch]	#新建一个分支,与指定的远程分支建立追踪关系

#=== 切换分支 ===#
git checkout -				#切换到上一个分支。
git checkout [branch-name]	#切换到指定分支。
git checkout --track 远程仓库名/分支名		#如果本地代码关联多个远程仓库,且仓库之间有相同的分支名,则需用这种方法

#=== 合并分支 ===#
git rebase [branch]	#合并指定分支到当前分支
git merge [branch]	#合并指定分支到当前分支
	--no-ff		#加上该参数就可以查看到合并分支图,查看方式:git log --graph
	# dev_1和dev_2会往master上合,用git rebase和git merge分别合入后,master变化区别
	     ---E---F---> dev_1
	    |
	A---B------> master,是当前分支
	    |
	     ---C---D--->dev_2
	# git rebase dev_1
	# git rebase dev_2
	A---B---E---F---C---D---> master # 按照commit时间排
	# git merge dev_1
	# git merge dev_2
	A---B-------------------G---> master	# 按照merge合入次序排
		|					|
		 ---E---F---C---D---
	# 如果再执行:git rebase -i commit_B,效果与git rebase合并两分支就一样了
# rebase步骤:先合并 -> 解决冲突 -> git add -> git rebase --continue -> git push
# merge步骤:先合并 -> 解决冲突 -> git add file-> git commit-> git push
# 如果想回到合并之前的代码,git merge/rebase --abort终止合并即可

#=== 删除分支 ===#
# Git会自行负责分支的管理,所以当我们删除一个分支时,Git只是删除了指向相关提交的指针,但该提交对象依然会留在版本库中。
git branch -d [branch-name]			#删除一个没有被打开的分支
git branch -D <branch_name>			#删除一个正打开的分支
git branch <branch_name> <hash_val>	#在已知提交的散列值的情况下恢复某个分支

#=== 更新远程分支列表 ===#
# 由于在远程删除了分支,有时候本地不能更新到,所以再次操作已删除的分支时git会报错, 此时只需要刷新一下分支列表即可正常操作
git remote update origin --prune
git remote update origin --p

4.2 查看/新建/推送/删除标签

tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起。

# 查看标签
git tag             # 列出所有标签名,按字母排序
git show <tagname>  #查看tag信息及其所对应的commit的信息

# 创建标签
git tag <name>
git tag v1.0                                #默认标签是打在最新提交的commit上的
git tag v1.0 commit_id                      #在指定的commit上打标签
git tag -a name -m "tag message" commit_id  #-a指定标签名,-m指定说明文字

# 推送标签
git push origin <tagname>   #推送指定标签到远程
git push origin --tags      #一次性推送全部尚未推送到远程的本地标签

# 删除标签
git tag -d <tagname>                    #删除一个本地标签
git push origin :refs/tags/<tagname>    #删除一个远程标签(先删除本地)
    # 删除已经推送至远程的标签v0.1
    # git tag -d v0.1
    # git push origin :refs/tags/v0.1

五、常用操作总结

5.1 提交代码至GitHup

初始化一个仓库,将修改该的代码全部提交到GitHup上。

git init 
git add .
git commit -m "messenge"
git remote add origin [url]
git push -u origin br_name	#第一次推送需要-u,后续不再需要
	-u	Git不但会把本地的br_name分支内容推送的远程新的br_name分支,还会把本地的br_name分支和远程的br_name分支关联起来

5.2 修改指定commit的内容

现在有以下三条提交内容,前两条commit是我们推上社区的,第三条是社区已经合入的最新commit。

# 我们提交的最新一次commit,就叫commit_1
commit 6675bf2fbd96ca755c8a2610c50fd1ac600c5d44 (HEAD -> master, tag: master.mailed)
       ...
    Change-Id: Ie80dbae738f60df6c11a3fe31fc57de817d76afc

# 我们提交的倒数第二新commit,就叫commit_2
commit 04c7e2f6ddc00e881d9f26dd6acadd744f650ce2
        ...
    Change-Id: I7ff3c8df24ed7990fe104bc2530354c0bd5fe018

# 远程仓库中合入的最新commit,就叫commit_3
commit b37c0602cdc9b7f13b3d539663e68b12f10b44b1 (origin/master, origin/HEAD)
Author: qmuntal <quimmuntal@gmail.com>
Date:   Mon Mar 13 14:34:38 2023 +0100
        ...

假设现在我们commit了两次,也就是打算用两个补丁将内容推上社区。社区检查发现,commit_1的某个文件file_1代码和提交描述信息都不对,我们可以按照下面的方式来修改。

#修改文件file_1代码
git add file_1
git commit --amend	#修改描述信息,保存退出
git push ...		#将这次对commit_1的修改推上远程仓库

我们推上社区后,检查又发现,commit_2的描述信息有误,所以我们需要在本地修改,然后再向上推。

git rebase -i b37c0602cdc9b7f13b3d539663e68b12f10b44b1	#commit_3
	#命令执行完后会自动打开一个类似于下面的文件,将commit_2的pick改成reword,然后保存退出
	reword 350ce6d57b ...		#commit_2
	pick effb5f88d7 ...		#commit_1
		...
# 上面操作退出后,又弹出一个新的框,让我们更改commit信息,编辑完后退出就好了
git push ...	#推上远程仓库

推上社区后,检查又发现,commit_2的某个文件file_2不对,所以我们需要在本地修改,然后再向上推。

#修改文件file_2代码
git add file_2
git commit --fixup 04c7e2f6ddc00e881d9f26dd6acadd744f650ce2	#commit_2
git rebase --autosquash -i b37c0602cdc9b7f13b3d539663e68b12f10b44b1	#commit_3
	#上面命令执行完后会自动打开一个文件,不用改任何东西,然后保存退出
		...
git push ...	#推上远程仓库

社区检查又发现,commit_2的某个文件file_2代码也不对,我们修改提交方式和commit_1中采用的第二种方式相同,只要将commit_1换成commit_2即可。如果commit_2的文件和描述信息都有误,我们可以按照下面方式来修改提交,这个就是前面两种方式的结合。

#修改文件file_2代码
git add file_2
git commit --fixup 04c7e2f6ddc00e881d9f26dd6acadd744f650ce2	#commit_2
git rebase --autosquash -i b37c0602cdc9b7f13b3d539663e68b12f10b44b1	#commit_3
	#命令执行完后会自动打开一个类似于下面的文件,将commit_2的pick改成edit,然后保存退出
	edit 350ce6d57b ...		#commit_2
	pick effb5f88d7 ...		#commit_1
		...
git commit --amend		#开始对commit_2的描述信息修改,然后保存退出,这条命令可以多次使用
git rebase --continue	#等commit_2的描述信息修改该好了,最后再执行这条命令
git push ...	#推上远程仓库

5.3 将多个commit合并为一个

继续使用5.2中的三次commit信息,现在我们要将commit_1和commit_2这两条commit信息合并为一条新的commit。可以下面的做法来完成:

git rebase -i b37c0602cdc9b7f13b3d539663e68b12f10b44b1 #commit_3
	#命令执行完后会自动打开一个类似于下面的文件,将commit_1的pick改成squash,然后保存退出
	pick 350ce6d57b ...		#commit_2
	pick effb5f88d7 ...		#commit_1
	pick ....				#如果三个压缩一个,继续pick改成squash
# 上面操作退出后,又弹出一个新的框,让我们更改commit信息,编辑完后退出就好了

5.4 项目生成/合入patch

修改的内容尚未commit时,打patch以及将patch打入到项目中的方法如下:

#生成patch文件
git diff ... > xxx.patch

#将patch打入到项目
patch -pN -i patch_path/xxx.patch
# -p 指定patch文件中除去几层目录,也就是去掉几个/,如其中某个路径为/src/cmd/compile/internal/ssa/regalloc.go
#   -p0 使用完整路径名,/src/cmd/compile/internal/ssa/regalloc.go
#   -p1 去掉一个/,src/cmd/compile/internal/ssa/regalloc.go
#   -p4 除去4个前导斜杠和前三个目录,internal/ssa/regalloc.go
# -i patch-file,不用这个参数也可以:patch -pN < patch_path/xxx.patch

git format-patch HEAD生成的patch也可以patch -pN -i xxx.patch打入工作区代码。修改的内容已经commit时,打patch以及将patch打入到项目中的方法如下(参考链接):

# 生成patch文件,有几个^就会打几个patch,从最近一次打起
git format-patch HEAD^					#为最近一次commit打patch,有几个^就打包最近几个patch的内容
git format-patch -n1 -n2				#打包版本n1与n2之间的patch
git format-patch commit_id				#commit_id(不含)之后的所有patch
git format-patch -n commit_id			#commit_id(含)之前的n次commit打patch
git format-patch commit_id1..commitid2	#(commit_id1, commitid2]之间的所有commit打patch
git format-patch xxx --stdout > xxx.patch	#将所有patch输出到一个指定位置的指定文件
	-- numbered-files	#文件名只有编号,不包含提交信息
	-o <dir>			#指定patch的存放目录
	
# 打入patch
# 方式1:打入到工作区,不会生成comit
	git apply --reject xxx1.patch xxx2.patch ...
		#自动合入 patch 中不冲突的代码改动,同时保留冲突的部分
		#这些存在冲突的改动内容会被单独存储到目标源文件的相应目录下,以后缀为 .rej 的文件进行保存
		--stat		# 查看patch中修改的文件
		--check		# 测试patch是否能应用到当前分支
	find -name *.rej
		#查看所有存在冲突的源文件位置
		#逐个手动解决冲突,然后删除这些 *.rej 文件

# 方式2:打入到本地仓库,会生成commit
	git am xxx1.patch xxx2.patch ...
		#将patch打入到项目,如果遇到冲突,会暂停不再继续打入后续patch
		#此时我们依然处于git am命令的运行环境中
	git am --show-current-patch		#查看失败的patch内容
	# 如果有冲突则需要以下操作
	git apply --reject xxx1.patch	#修改产生的冲突文件
	git add . 				#将所有改动都添加到暂存区,patch中合入的代码也会要add
	git am --continue		#git add冲突代码后执行,继续打入后续patch(也可执行git am --resolved)
	# 如果这个冲突没必要解决,直接跳过,继续打入后续patch
	git am --skip					#跳过此次冲突
	# 如果想恢复打入patch之前的代码
	git am --abort			#回退打入patch的动作,还原到操作前的状态

5.5 保存工作区变化

在切换分支的时候,如果工作区内容有变化,我们是无法切换分支的。

当我们从master拉出一个分支branch_1,开始在branch_1上工作并写了一些代码。此时如果master上面发现了一个紧急的bug,我们要暂停手上的活去定位master上的bug,但是我们的本地的branch_1分支已经有了我们新写的代码,我们需要将这些新写的代码保存到某个地方,然后让branch_1分支的代码和master上的代码一样,再去解决问题。

git stash就是保存这些代码的一个地方,其结构是个栈,将当前未提交的修改(即,工作区的修改和暂存区的修改)先暂时储藏起来,这样工作区干净了后,就可以切换切换到master分支下拉一个branch_2分支。在完成紧急bug的修复工作后,将branch_2分支合入master分支,然后重新切换到branch_1分支下通过git stash pop命令将之前储藏的修改取出来,继续进行新功能的开发工作。(参考链接

git stash list					#查看所有的stash
git stash show -p stash@{num}		#查看某个stash具体内容

#把所有未提交的修改(包括暂存的和非暂存的)都保存起来,
#save_message是描述存储代码的信息,方便恢复的时候区分,还是很有必要
git stash save "save_message"

git stash pop				#将缓存堆栈中的第一个stash删除,并将对应修改应用到当前的工作目录下
git stash apply	stash@{num}	#将缓存堆栈中的stash多次应用到工作目录中,但并不删除stash拷贝

git stash drop stash@{num}		#删除指定stash@{num}
git stash clear					#删除所有缓存的stash

将master分支上的bug修复了以后,我们要想一想,branch_1分支是早期从master分支分出来的,所以,这个bug其实在当前branch_1分支上也存在。那怎么在branch_1分支上修复同样的bug?

  1. 将master分支上提交该bug的commit打一个patch,然后将该patch打入到branch_1分支。
  2. 找到master分支该bug的commit id,然后在branch_1分支执行git cherry-pick commit_id
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yelvens

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值