Git总结
本文会持续更新,欢迎各位私信指正~~
介绍
工作区:就是电脑里本地能看到的目录,它持有实际文件。
缓存区/暂存区:英文名叫 stage 或 index。在执行git add命令之后,会把工作区的修改记录添加到缓存区以便跟踪。它像个缓存区域,临时保存你的改动。
说明:缓存区的文件一般存放在 .git 目录下的 index 文件(.git/index)中,所以我们把暂存区也叫作索引(index)。
版本库/本地仓:英文名Repository,管理代码版本的地方,在执行git commit命令之后,会把缓存区的修改记录提交到版本库里。
说明:在一个空文件下,执行git init命令之后,会在该文件下创建一个版本库(.git),它是一个隐藏的目录。
常用操作
一. 放弃本地修改
1、没有add 的
$ git restore <某文件>… #在工作区,撤销对某文件的修改
如果需要放弃所有文件里的修改,使用git restore .
放弃本地修改。
说明:此命令只针对已经修改的内容和已经删除的文件,但不会删除刚新建的文件,因为刚新建的文件还没有加入到git的管理系统中。所以对于git来说,刚新建的文件是未知的,自己动手删除即可。
2、已经add的
情况说明:已经修改的文件已经add到暂存区/缓存中了,但是没有commit,此时如果不想提交这个文件的修改。
$ git restore --staged <某文件>…
如果是放弃所有修改,直接使用git restore --staged .
3、已经commit的
1)使用场景:已经push的代码有问题,需要修改后重新push。
不回退/不删除工作区里的已修改的代码,撤销commit,保留add操作,需要再次提交时直接commit就可以,也就是已经push到本地和远程库的代码不会受到影响,只是提交的版本信息回退了。
$ git reset --soft <commit_id>
2) 使用场景:
不回退/不删除工作区里的已修改的代码,但会撤销commit和add操作。
$ git reset --mixed <commit_id>
3)使用场景:
回退/删除工作区里的已修改的代码,并且撤销commit和add操作。
$ git reset --hard <commit_id>
此操作会将本地代码彻底回退到指定的版本,已修改的代码也都不复存在,全部回退到某个版本,相当于清空某个版本以后的提交记录。
另外,上面三种方式是按照commit_id回退的,也可以按照提交次数回退:
$ git reset --hard HEAD^^或者gitreset --hard HEAD~2 #回退2次
git pull时出现自动合并冲突时,可以使用git merge --abort
终止合并,使用 git merge --abort
是安全的,因为它不会影响您的工作目录或暂存区中的文件,只会撤销当前正在进行的所有合并操作,包括那些已经自动完成的部分。
4、全部与远程仓同步,强制覆盖本地修改。
1) $ git fetch --all // 拉去所有的更新,不同步;
2) $ git reset --hard origin/master // 本地代码
同步远程最新版本(会覆盖本地所有与远程仓库上同名的文件),git reset指令把HEAD指向master最新版本。
3) $ git pull // 再次更新,其实也可以不用执行这一步,因为第2步命令已经保证了与远程仓相同。
简化命令:$ git fetch --all && git reset --hard origin/master && git pull
5、忽略不需要提交的文件
1)忽略已经跟踪的文件:
说明:对于库上已存在的文件,但本地已经产生变化的文件且不影响项目的修改,可以标记为"已修改但不关心的修改"
临时忽略:git update-index --assume-unchanged <需要忽略的文件> //注意:如果pull文件后,会被取消忽略
取消临时忽略:git update-index --no-assume-unchanged <需要忽略的文件>
忽略:git update-index --skip-worktree <需要忽略的文件>
取消忽略:git update-index --no-skip-worktree <需要忽略的文件>
查询被忽略的文件:git ls-files -v | grep -i ^S
2)忽略未跟踪的文件(Untracked):
1 .gitignore
touch .gitignore新建一个.gitignore文件。可以使用vim .gitignore
编辑并添加需要忽略的文件路径,最后提交.gitignore文件。
注意:这个.gitignore这个文件默认会被提交入库,它主要是忽略本地新增的目录或者文件。
2 git config --global core.excludesfile
3 git/info/exclude
二. 分支管理
git branch branchname // 新建分支branchname
git branch // 查看本地所有分支
git branch -a //查看本地和远程所有分支
git branch -r //查看远程所有分支
git branch -d branchname //删除本地分支(-d不生效时可以使用-D)
git branch -m oldbranchname newbranchname // 重命名分支
1、处理游离状态detached
- 如果在游离状态没有修改,可以直接切换正常分支
git checkout workbranch - 如果将游离状态的修改,合并到新建分支:
git checkout -b workbranch - 如果将游离状态的修改,合并到已有分支:
1)基于当前的修改创建一个临时分支tempbranch
$ git branch tempbranch hash值 //hash值是游离状态的hash码
2)切换到某个工作分支
$ git checkout workbranch
3)将tempbranch及修改合并到工作分支
$ git merge tempbranch
2、将A分支的一笔提交合并到另一个B分支
1)获取A分支上的需要合并的那一笔commit-id
$ git log #找到需要合并的id
2)切换到B分支
$ git checkout <B分支名称>
3)将A分支上的提交合并到B分支
$ git cherry-pick
3、解决冲突conflict
3.1 查看存在冲突的文件。
$ git status # 使用 git status 命令查看哪些文件存在冲突
3.2 手动解决冲突。
打开有冲突的文件,会看到类似如下的标记
<<<<<<< HEAD
本地代码
=======
远程代码
>>>>>>> 分支名
根据实际情况保留需要代码,删除不需要的代码。
3.3 将所有修改过的文件重新加入暂存区 。
$ git add . # 添加之后可以查一下修改git diff .
3.4 冲突场景
场景1:如果是从远程分支cherry-pick到本地时,提示异常:
$ git cherry-pick --continue # 继续合并
$ git cherry-pick --abort # 放弃合并
$ git cherry-pick --quit # 退出合并
场景2:如果是从本地push到远程仓时,远程仓拒绝推送请求rejected:
(1)先拉取后合并
$ git pull origin master
(2)解决冲突
操作步骤同3.1~3.3
(3)提交合并结果,最后重新推送。
$ git commit -m "解决与远程仓库的冲突"
$ git push origin master
三. 仓库管理
修改本地仓关联的远程仓
1、查看当前配置的远程仓库和URL
$ git remote -v
2、修改远程仓库的名称或URL
方式一:直接修改远程仓库URL
$ git remote set-url <远程仓库名,如origin> <URL>
方式二:先删除旧的,再添加新的远程仓库
$ git remote rm origin
$ git remote add <远程仓库名,如origin> <URL>
四、补丁用法
补丁有两种用法,diff和format-patch,他们的区别:
git diff 生成补丁时可以自定义补丁名称,补丁不包含已提交的信息commit message。
git format-patch 生成补丁时无需指定补丁名称,补丁包含已提交的信息commit message。
git apply不会将commit message等打上去,打完patch后需要重新git add和git commit。
git am会直接将patch的所有信息打上去,无需重新git add和git commit。
方式一:diff
1. 生成补丁
// 将所有修改都写入补丁
git diff > test.patch
// 指定某个文件的修改写入补丁
git diff 文件名 > test.patch
// 已经执行git add后,也想写入补丁
git diff --cached > test.patch
// 将已经提交的代码,也想写入补丁
// git log查看需要打ptach的commit id区间,其中commit_id1的时间戳大于commit_id2。
git diff commit_id1 commit_id2 > test.patch
2. 查看补丁
git apply --check test.patch
3. 使用补丁
git apply test.patch
方式:format-patch(推荐)
1. 生成补丁
// 生成commitid对应的补丁
git format-patch -1 commit_id
// 将commit_id之后的所有修改都写入补丁,自动生成补丁名称,如xxx.patch
git format-patch commit_id
// 已经提交的代码,也想写入补丁
// 生成两个commit间的修改的patch
git format-patch commit_id1 commit_id2
// 将最近几次提交的修改写入补丁,比如这里提交最近三次的修改
git format-patch -3 //或者git format-patch HEAD^^^
2. 查看补丁
git apply --check 系统自动生成的补丁名称
3. 使用补丁
// 使用补丁,也称打补丁
git am xxx.patch
// 添加-s或者–signoff,可以注明打patch的人
git am --signoff xxx.patch
// 将路径~/patch-set/下的所有补丁,会按照先后顺序全部打上。
git am ~/patch-set/*.patch
解决合并冲突
// 检查patch是否能够打上,如果没有任何输出,则说明无冲突可以打上,直接git am xxx.patch
git apply --check xxx.patch
// 如果出现patch does not apply则表示有冲突,则需要强制打补丁
git apply --reject xxx.patch
// 强制打补丁时,没有冲突的修改会自动合入。
// 有冲突的会自动生成xxx.rej文件(如xxx.java.rej),需要手动解决冲突。
手动修改解决完成以后,通过 git add files添加修改。----此时这个xxx.rej会自动消失吗?
// 需要丢弃此次合并过程中的所有修改,回到没有合并之前的状态
git am --abort
// 暂时不能解决但想后面再继续解决
git am --skip
// 解决完合并冲突后,回复commit信息。
git am --resolved // 等同于git am --continue
// 重新打补丁
git am xxx.patch
常用API
checkout用法
- git checkout
显示工作区相对于版本库修改过的文件。git checkout和git status的区别是git checkout没有显示未跟踪文件(Untracked files:),而git status则显示未跟踪的文件。 - git checkout 分支名
表示切换分支 - git checkout -b <新分支名> // 新建并切换至新分支
Detail:表示以当前分支的当前状态来创建新分支并切换到新分支 -b 表示创建新分支 - git checkout -b <新分支名> commitId
表示以当前分支的commitId提交节点创建新的分支并切换到新分支。此时工作区的内容和切换分之前commitId提交节点的内容一样。 - git checkout .
表示将工作区的所有文件的内容恢复到暂存区的状态。这里暂存区的状态是指暂存区原来的状态,也就是现在要扔掉没有加入到缓存区的所有文件。 - git checkout filename
表示将工作区的指定文件的内容恢复到暂存区的状态。这里暂存区的状态是指暂存区原来的状态,也就是现在要扔掉没有加入到缓存区的指定文件。 - git checkout commitId filename
表示将工作区和暂存区的指定文件都恢复到指定版本的状态,此时的HEAD指针不变。即就是把工作区的指定文件(filename)修改到指定版本后(也就是扔掉后),再把当前状态的该文件(这里指commitId版本的修改)添加到暂存区,这也就是执行此命令后,就可以直接执行git commit而不需要先执行git add。相当于版本回退吗? - git checkout commitId
表示以指定的提交节点commitId创建了一个临时性分支,此临时性分支可用于做实验性修改。注意:此时HEAD不位于任何分支上,处于游离状态。更准确的说,此命令是以指定的提交节点创建了一个临时分支,一个临时的HEAD指向了这个临时分支,可以在这个临时分支上修改内容并且提交内容。但从临时分支切换到原有分支或其他分支,这个临时分支就会消失,并且在临时分支上的实验性修改也会消失,不影响原有分支。
push用法
git push指令的基本功能是将本地的分支更新推送到远程仓库中。这意味着当你在本地完成了代码的修改、提交(commit)之后,可以使用git push将你的更改同步到远程仓库,以便其他协作者可以看到并获取你的更新。
git push指令的常用语法格式
- 基本格式:
git push <远程仓库名> <本地分支名>:<远程分支名>
如果不指定远程分支名,Git会尝试将本地分支推送到与本地分支同名的远程分支(如果远程分支存在的话)。
- 常用简化格式(如果本地分支和远程分支同名):
git push <远程仓库名> <本地分支名>
或者,如果只配置了一个远程仓库,并且想要推送到该仓库的默认分支(通常是master或main),可以进一步简化为:
git push <本地分支名>
或者
git push
(后者在本地分支已经配置了跟踪的远程分支时有效)
- 使用-u或–set-upstream来设置上游分支(较常用)
当你第一次推送一个分支到远程仓库时,可以使用-u或–set-upstream选项来设置上游(即跟踪的远程分支),这样以后你就可以直接运行git push
而不需要指定分支名了。
git push -u <远程仓库名> <本地分支名>:<远程分支名>
git push指令的使用示例
假设你的远程仓库名为origin,并且你想要将本地的main分支推送到远程的main分支,你可以这样做:
git push origin main
如果你想要将本地的feature-branch分支推送到远程的同名分支,并设置上游跟踪,可以这样做:
git push -u origin feature-branch:feature-branch
或者,如果远程分支已经存在并且与本地分支同名,可以简化为:
git push -u origin feature-branch
git push常见问题及解决方法
- 权限问题:如果推送失败并提示权限不足,确保你有权向远程仓库推送代码。你可能需要检查你的远程仓库URL是否正确,以及你是否已经使用正确的凭据(如用户名和密码或SSH密钥)进行了身份验证。
- 分支不存在:如果远程仓库中没有你尝试推送的分支,并且你没有使用正确的语法来创建远程分支,Git会报错。确保远程分支名正确,或者使用git push origin local-branch:new-remote-branch来创建新的远程分支。
- 网络问题:推送失败也可能是由于网络问题。检查你的网络连接,并尝试再次推送。