什么是Git?
概念
Git是版本管理系统,简单的说就是追踪并管理我们文件的变化
Git中的HEAD、head和master
关系图解:https://juejin.im/entry/59a38c5d6fb9a0248e5cc884
HEAD 当前活跃分支的游标(让Git知道你在哪)== current branch
head commit对象的引用,一个repository可以包含任意数量的head。
head被选择成为”current head“,head就成了HEAD
master 分支,会有一个head
Git 命令
基础命令
https://www.ruanyifeng.com/blog/2014/06/git_remote.html
git clone
从远程主机克隆一个库,所用命令
$ git clone <库网址> // 指定不同的目录名 $ git clone <库网址> <本地目录名> // 多种协议 HTTP(s)、SSH、Git(最快)等 $ git clone http[s]://example.com/path/to/repo.git/ $ git clone ssh://example.com/path/to/repo.git/ // 克隆库所使用的远程主机自动被命为origin // 想使用其他的主机名,需用git clone命令的-o指定。 $ git clone -o <主机名> <库网址>
git checkout
//从dev切换回开发分支时,要是dev某个文件跟开发分支冲突时,他就会弹出一个窗,说这部分文件冲突,问你要怎么处理 smart checkout就会把冲突的这部分内容带到开发分支(没有点进窗口的那些文件处理冲突的话) force checkout就不会把冲突的这部分内容带到开发分支
git remote
管理远程主机,所用命令
// 列出所有远程主机名 $ git remote //origin // 列出所有远程主机和远程主机的网址 $ git remote -v //origin [email protected]:jquery/jquery.git (fetch) //origin [email protected]:jquery/jquery.git (push) // 查看主机详细信息 $ git remote show <主机名> // 添加远程主机 $ git remote add <主机名> <网址> // 删除远程主机 $ git remote rm <主机名> // 远程主机的改名 $ git remote rename <原主机名> <新主机名>
git fetch
将远程库的更新取回本地
// 远程主机全部更新取回本地 $ git fetch <远程主机名> // 远程主机特定分支取回本地 $ git fetch <远程主机名> <分支名>
git pull
取回远程主机某个分支的更新,再与本地的指定分支合并
git pull = git fetch + git merge
// 取回远程回到本地分支并合并 $ git pull <远程主机名> <远程分支名>:<本地分支名> // 取回远程回到本地当前分支并合并 $ git pull <远程主机名> <远程分支名> // Git自动建立追踪关系,默认同名分支建立追踪关系 $ git pull origin // 如果当前分支只有一个追踪分支 $ git pull // 手动建立追踪关系 // 指定master分支追踪origin/next分支 git branch --set-upstream master origin/next // 在本地删除远程已经删除的分支,不加p默认不会删除 $ git pull -p // 合并如果需要rebase,这么写: $ git pull --rebase <远程主机名> <远程分支名>:<本地分支名>
git commit
// git commit方法很简单,主要注意配置项 // --amend 可以用来对上次的提交进行修改 $ git commit --amend // 使用注意事项: // 如果commit已经push到远程了,此时amend之后,又希望push,需要-f,因为本地commit和远程commit不一样 // 注意同事如果针对旧commit开发了,amend这样的做法可能会产生影响 // 所以没有push过的commit可以随意修改,但是push上去后,就需要斟酌了
git push
将本地分支的更新,推送到远程主机
$ git push <远程主机名> <本地分支名>:<远程分支名> // 可省略远程分支名,远程分支不存在会重建 $ git push <远程主机名> <本地分支名> //省略本地分支,则表示删除远程某分支(推空上去) $ git push <远程主机名> :<远程分支名> // 远程本地分支间存在追踪关系 $ git push // 多个远程主机,可指定默认主机 $ git push -u <远程主机名> <本地分支名> // push的 simple 方式,默认只推送当前分支 $ git push // push的 matching 方式,默认会推送所有有对应远程的本地分支 // 修改push的方式: $ git config --global push.default <push类型> $ git push // 这样push就会变成对应类型的push // push 本地所有分支到远程 $ git push --all <远程主机名> // push **注意事项**: // 远程版本比本地版本新,push会报错,此时: $ git pull // 合并差异 $ git push // 如果确定不合并差异要push: $ git push --force <远程主机名> // push推送标签,默认不push标签 $ git push <远程主机名> --tags
其他常用命令:
git branch
查看分支
// 查看远程分支 $ git branch -r // 查看所有分支 $ git branch -a * master remotes/origin/master // 本地主机的当前分支是master,远程分支是origin/master
git checkout
// 取回远程更新后,可使用git checkout命令创建一个新的分支 $ git checkout -b newBrach <分支名> origin/master
进阶命令
git reset 和 git revert
https://juejin.im/post/5b0e5adc6fb9a009d82e4f20
都是回退命令,如果想回退commit 2
$ git reset --参数 --soft 回退后2修改的代码被保留并标记为add的状态(git status 是绿色的状态) --mixed 重置索引,但不重置工作树,更改后的文件标记为未提交(add)的状态。默认操作。 --hard 重置索引和工作树,并且2分支修改的没有了。 --merge 和--hard类似,只不过如果在执行reset命令之前你有改动一些文件并且未提交,merge会保留你的这些修改,hard则不会。 简单理解: // commit2想回退并不需要代码: git reset commit1_ID --hard 远程有之前代码,强推 git push -f // commit2想回退但是保留代码 it reset commit1_ID // 会直接把回退的commit删除掉
// commit2想回退掉 $ git revert commit2_ID //新增一个commit,把之前2的修改都改回去了
区别:
- commitID不一样,使用时注意
- reset之后没有commit记录,revert因为是新增一个commit,可看到commit记录;所以reset 是把HEAD向后移动,而git revert是HEAD继续前进,只是新的commit的内容和要revert的内容正好相反,能够抵消要被revert的内容
- 同事间协作,revert更好,提醒同事这里有回退操作
- 如果不希望commit2之后的3、4消失,只能用
git revert commit2_ID
cherry-pick
http://www.ruanyifeng.com/blog/2020/04/git-cherry-pick.html
将指定commit应用于其他分支。
将代码从一个分支转移到另一个分支:
- 需要另一个分支的所有代码变动,git merge
- 只需要部分代码变动(某几个提交),Cherry pick
// 将指定的提交commitHash,应用于当前分支。这会在当前分支产生一个新的提交,哈希值不一样。 // commitHash不写默认最新一次 $ git cherry-pick <commitHash> // 转移多个提交,两种 $ git cherry-pick <HashA> <HashB> <HashC> <HashD> $ git cherry-pick A^..D // 配置 // 只更新工作区和暂存区,不产生新的提交。 $ git cherry-pick A^..D --no-commit // 发生代码冲突,cherry pick会停下来 // 如果已处理好冲突 $ git add . $ git cherry-pick --continue // 发生代码冲突后,放弃合并,回到操作前的样子。 $ git cherry-pick --abort // 发生代码冲突后,退出 Cherry pick,但是不回到操作前的样子 $ git cherry-pick --quit // 不仅同一个代码库不同分支可以,不同代码库也可以 $ git remote add <库名> <地址> // 添加了一个远程仓库 $ git fetch target // 将远程代码抓取到本地 $ git fetch target // 从远程仓库转移的提交,获取它的哈希值 $ git cherry-pick <commitHash> // 转移提交
git rebase
https://www.jianshu.com/p/4a8f4af4e803
主要是对分支做变基操作,主要的用途:
- 分支已经过时落后,需要执行rebase来同步分支的变动
// 一同开发出现冲突,一般比如本地master分支落后了 $ git pull $ git rebase $ git push //上面三个指令可合并为一个 $ git pull --rebase
- 分支合并:
从master分支切除新分支用于开发,此时master分支又有了新的commit,这是希望自己开发的分支同步这些新提交,有两种方法,merge和rebase,两者的区别如下图,简单的说就是merge会污染commit记录,rebase的commit很干净。
// 当前分支rebase到master分支上 $ git rebase master // rebase实际处理 // <1>把 dev 分支里面的每个 commit 取消掉; // <2>把上面的操作临时保存成 patch 文件,存在 .git/rebase 目录下; // <3>把 dev 分支更新到最新的 master 分支; // <4>把上面保存的 patch 文件应用到 dev 分支上; // rebase时出现冲突,git 会停止rebase去解决冲突。在解决完冲突后,用 $ git add . // 更新内容 $ git rebase --continue // 继续余下的patch // 终止rebase,dev回到之前状态 $ git rebase —abort
- 合并多个commit:
在开发时,经常对于一个功能开发,有多次commite提交,此时需要把多个commit合并再push
// 合并最近的 4 次提交纪录 $ git rebase -i HEAD~4 $ git rebase -i 要合并的版本之前的版本号 // 自动进入 vi 编辑模式,其中有几个命令,可用来自定义各种合并和提交,:wq保存并退出 p, pick = use commit r, reword = use commit, but edit the commit message e, edit = use commit, but stop for amending s, squash = use commit, but meld into previous commit f, fixup = like “squash”, but discard this commit’s log message x, exec = run command (the rest of the line) using shell d, drop = remove commit // 例子,多个最后合并weiyige s commitID s commitID s commitID p commitID // error: cannot 'squash' without a previous commit // 此错误是因为合并里面,有已经push的commit,不可以哦 // 退出vi,希望重新进入 $ git rebase --edit-todo //修改完继续 $ git rebase --continue
注意:
因为该操作是危险操作,需注意
- dev分支只有自己使用,可以rebase操作
- dev分支上需要 rebase 的所有 commit 历史还没有被push过,就可以安全地使用rebase来操作。
Git 实际使用场景总结
- 实际使用时,经常会出现一些冲突(比如git stash pop的文件会和改动的代码有冲突),解决完冲突后,均需git add . ,再进行接下来的操作。