git
作为当前最流行的代码管理工具,用好 git
可以有效的提高团队开发效率
常用命令
git add
|
git commit
|
git fetch
将某个远程主机的更新,全部/分支 取回本地(此时之更新了 Repository)它取回的代码对你本地的开发代码没有影响,如需彻底更新需合并或使用 git pull
git pull
拉取远程主机某分支的更新,再与本地的指定分支合并(相当与 fetch 加上了合并分支功能的操作)
git push
将本地分支的更新,推送到远程主机,其命令格式与 git pull
相似git push -f
强制推送( 如果本地commit和远程commit有冲突时,覆盖远程commit
)
分支操作
- 使用 Git 下载指定分支命令为:
git clone -b 分支名仓库地址
- 拉取远程新分支
git checkout -b serverfix origin/serverfix
- 合并本地分支
git merge hotfix
:(将 hotfix 分支合并到当前分支) - 合并远程分支
git merge origin/serverfix
- 删除本地分支
git branch -d hotfix
:(删除本地 hotfix 分支) - 删除远程分支
git push origin --delete serverfix
or
|
- 上传新命名的本地分支:
git push origin newName
; - 创建新分支:
git branch branchName
:(创建名为 branchName 的本地分支) - 切换到新分支:
git checkout branchName
:(切换到 branchName 分支) - 创建并切换分支:
git checkout -b branchName
:(相当于以上两条命令的合并) - 查看本地分支:
git branch
- 查看远程仓库所有分支:
git branch -a
- 本地分支重命名:
git branch -m oldName newName
- 重命名远程分支对应的本地分支:
git branch -m oldName newName
- 把修改后的本地分支与远程分支关联:
git branch --set-upstream-to origin/newName
git 分支提交、合并常见问题
主分支领先当前分支
当前分支已经提交 commit
|
rebase
会自动合并领先的 commit
未提交 commit
不用切换分支,即可同步主分支最新代码
|
git 回退
git reset
删除指定的 commit
|
git revert
撤销 某次操作,此次操作之前和之后的 commit 和 history 都会保留,并且把这次撤销
作为一次最新的提交
|
git revert
是提交一个新的版本,将需要 revert
的版本的内容再反向修改回去,
版本会递增,不影响之前提交的内容
git revert
和 git reset
的区别
git revert
是用一次新的 commit 来回滚之前的 commit,git reset
是直接删除指定的 commit。- 在回滚这一操作上看,效果差不多。但是在日后继续 merge 以前的老版本时有区别。因为
git revert
是用一次逆向的 commit“中和”之前的提交,因此日后合并老的 branch 时,导致这部分改变不会再次出现,但是git reset
是之间把某些 commit 在某个 branch 上删除,因而和老的 branch 再次 merge 时,这些被回滚的 commit 应该还会被引入。 git reset
是把 HEAD 向后移动了一下,而git revert
是 HEAD 继续前进,只是新的 commit 的内容和要 revert 的内容正好相反,能够抵消要被 revert 的内容。
git commit 相关
git commit 提交多行 commit 信息
|
git 修改 commit 信息
1. 提交信息出错
更改 commit 信息
|
2. 漏提交
commit 时,遗漏提交部分更新,有两种解决方案:
- 方案一:再次 commit
|
此时,git 上会出现两次 commit
- 方案二:遗漏文件提交到之前 commit 上
|
--no-edit
表示提交消息不会更改,在 git 上仅为一次提交
修改历史的 commit
git rebase -i HEAD~3
表示要修改当前版本的倒数第三次状态.
这个命令出来之后,会出来三行东东:
|
如果你要修改哪个,就把那行的 pick 改成 edit,然后保存退出(点击 esc,输入 ZZ 退出)
这时通过git log
你可以发现,git 的最后一次提交已经变成你选的那个了,这时再使用:git commit --amend
来对 commit 进行修改。
修改完成后使用git rebase --continue
然后将变化 push 到远程:git push origin HEAD:master --force
git 合并多个 commit
过去总是使用 git reset --soft
回退到之前的状态,再 commit 后 push orgin master -f 强推到远程库,能够覆盖掉之前的 commit 。
但在团队协作时,每次 commit 前还需要 rebase upstream,这会自动将一些其他人做的修改也自动 merge 到本地的源码中。如果此时希望覆盖前一次 commit ,reset 到之前的状态后,再次 commit 的内容就包含了其他人的修改,这不是我们希望看到的。因此,我们需要使用 git rebase -i 。
基本步骤
- git log 查看所有 commit 的情况,找到自己想要合并的 commit 之前的那个 commit 的 ssh 码(前 7 位);
- git rebase -i 43jk2l3,这样会弹出一个文本编辑器;
撤销 commit
git reset –soft
HEAD^ 上个 commit
^^上上个 commit
HEAD~2 最近 2 次的提交 - 修改 pick 为 squash 会将这个 commit 合并到前一个 commit 中,保存退出;
- 提示写下新的 commit message,之前的 message 可以用#注释掉,保存退出;
- 此时再 git log 就会发现,两个 commit 被合并到一个 commit 中。
修改 push 到远程的 commit
- git log
- git rebase -i Head~8
- pick 修改为 edit
- git commit –amend 修改新的 commit message 保存 (修改作者信息 –author “luckyship xxx@xxx.com“)
- git rebase –continue // 处理完合并后 然后 git push -f 同理 git merge –continue
- git push -f
Commit message 前缀规范提要
code | info |
---|---|
feat:msg | 新功能 feature |
fix:msg | 修复 bug |
merge:msg | merge 信息 |
docs:msg | 文档修改 |
style:msg | 格式,不影响代码运行的变动 |
refactor: msg | 重构即不是新增功能,也不是修改 bug 的代码变动 |
test:msg | 增加测试 |
chore:msg | 构建过程或辅助工具的变动 |
rm:msg | 删除文件或代码 |
git stash(暂存区)
暂存
git stash
可用来暂存当前正在进行的工作,比如想 pull 最新代码又不想 commit , 或者另为了修改一个紧急的 bug ,先 stash,使返回到自己上一个 commit, ,改完 bug 之后再 stash pop , 继续原来的工作;
- 添加缓存栈:
git stash
; - 查看缓存栈:
git stash list
; - 推出缓存栈:
git stash pop
; - 取出特定缓存内容:
git stash apply stash@{1}
;
恢复误删除的 stash
|
在使用 git fsck –unreachable 命令输出的很多文件里面,有很多是带有 commit 和 tree 的标识的,这些可以使用 git stash apply 加标记号进行找回。而 blob 的文件是只能手动拷贝的,或者像上面一样使用> 输出到指定的路径去
rebase 和 mege 的区别
1. 拉取代码 pull –rebase
在团队协作过程中,假设你和你的同伴在本地中分别有各自的新提交,而你的同伴先于你 push
了代码到远程分支上,所以你必须先执行 git pull
来获取同伴的提交,然后才能 push
自己的提交到远程分支。
而按照 Git 的默认策略,如果远程分支和本地分支之间的提交线图有分叉的话(即不是 fast-forwarded),Git 会执行一次 merge
操作,因此产生一次没意义的提交记录,从而造成了像上图那样的混乱。
其实在 pull 操作的时候,,使用 git pull --rebase
选项即可很好地解决上述问题。 加上 --rebase
参数的作用是,提交线图有分叉的话,Git 会 rebase 策略来代替默认的 merge 策略。
假设提交线图在执行 pull 前是这样的:
|
如果是执行 git pull
后,提交线图会变成这样:
|
结果多出了 H
这个没必要的提交记录。如果是执行 git pull --rebase
的话,提交线图就会变成这样:
|
F
G
两个提交通过 rebase
方式重新拼接在 C
之后,多余的分叉去掉了,目的达到。
小结
大多数时候,使用 git pull --rebase
是为了使提交线图更好看,从而方便 code review。
不过,如果你对使用 git 还不是十分熟练的话,我的建议是 git pull --rebase
多练习几次之后再使用,因为 rebase 在 git 中,算得上是『危险行为』。
另外,还需注意的是,使用 git pull --rebase
比直接 pull 容易导致冲突的产生,如果预期冲突比较多的话,建议还是直接 pull。
注意:
git pull = git fetch + git merge
git pull –rebase = git fetch + git rebase
2. 合代码 merge –no-ff
上述的 git pull --rebase
策略目的是修整提交线图,使其形成一条直线,而即将要用到的 git merge --no-ff <branch-name>
策略偏偏是反行其道,刻意地弄出提交线图分叉出来。
假设你在本地准备合并两个分支,而刚好这两个分支是 fast-forwarded 的,那么直接合并后你得到一个直线的提交线图,当然这样没什么坏处,但如果你想更清晰地告诉你同伴:这一系列的提交都是为了实现同一个目的,那么你可以刻意地将这次提交内容弄成一次提交线图分叉。
执行 git merge --no-ff <branch-name>
的结果大概会是这样的:
|
中间的分叉线路图很清晰的显示这些提交都是为了实现 complete adjusting user domains and tags
更进一步
往往我的习惯是,在合并分支之前(假设要在本地将 feature 分支合并到 dev 分支),会先检查 feature 分支是否『部分落后』于远程 dev 分支:
|
如果没有输出任何提交信息的话,即表示 feature 对于 dev 分支是 up-to-date 的。如果有输出的话而马上执行了 git merge --no-ff
的话,提交线图会变成这样:
|
所以这时在合并前,通常我会先执行:
|
这样就可以将 feature 重新拼接到更新了的 dev 之后,然后就可以合并了,最终得到一个干净舒服的提交线图。
再次提醒:像之前提到的,rebase 是『危险行为』,建议你足够熟悉 git 时才这么做,否则的话是得不偿失的。
总结
使用 git pull --rebase
和 git merge --no-ff
其实和直接使用 git pull
git merge
得到的代码应该是一样。
使用 git pull --rebase
主要是为是将提交的线图平坦化,而 git merge --no-ff
则是刻意制造分叉。
git rebase 和 git merge 主要的区别在于是否保留分支的 commit 提交节点,rebase 会给你一个简洁的线性历史树。rebase 适合小分支,大分支还是使用 merge –squash。
git patch
git patch
会生成一个补丁文件,这样在不能直接 git pull
和 git push
的情况下,直接把补丁文件合入 git
项目中
|
git cherry-pick
现网发现了 bug,现网分支需要修改代码出补丁版本;同时,代码也要合入主干,保证主干版本没问题。
简言之,相同的代码,要合入两个分支,怎么办
|
同步 Github fork 出来的分支
1、配置 remote,指向原始仓库
|
2、获取上游分支
上游仓库获取到分支,及相关的提交信息,它们将被保存在本地的 upstream/master 分支
|
3、切换到本地的 master 分支
|
4、合并分支
把 upstream/master 分支合并到本地的 master 分支,本地的 master 分支便跟上游仓库保持同步了,并且没有丢失本地的修改。
|
5、上传到自己的远程仓库中
|
git 配置
邮箱和用户名
查看
|
修改
|
SSH
- 查看是否生成了 SSH 公钥
|
其中 id_rsa 是私钥,id_rsa.pub 是公钥。
- 如果没有那就开始生成,设置全局的 user.name 与 user.email
|
- 输入 ssh-keygen 即可(或
ssh-keygen -t rsa -C "email"
)
|
- 生成之后获取公钥内容,输入 cat ~/.ssh/id_rsa.pub 即可, 复制 ssh-rsa 一直到 .local 这一整段内容
|
- 打开 GitLab 或者 GitHub,点击头像,找到设置页
- 左侧找到 SSH keys 按钮并点击,输入刚刚复制的公钥即可
git push 报 HTTP Basic: Access denied 错误
- 永久记住密码
git config --global credential.helper store
如果没 --global
,则在当前项目下的.git/config 文件中添加。
- 默认记住 15 分钟
git config –global credential.helper cache
- 自定义配置记住 1 小时:
git config –global credential.helper ‘cache –timeout=3600’
解决方案:
- 如果账号密码有变动 用这个命令
git config --system --unset credential.helper
(清除用户名密码)重新输入账号密码应该就能解决了 - 如果用了第一个命令 还不能解决问题那么 用这个命令:
git config –global http.emptyAuth true
文件名过长错误
Filename too long warning: Clone succeeded, but checkout failed.
|
.gitignore
更新后生效:
|
git commit -v
使用 vim
|
git 统计
查看 git 上个人代码量
|
统计每个人的增删行数
|
查看仓库提交者排名前 5
|
贡献者统计
|
提交数统计
|
参考
本文参考了
git 相关问题场景和命令
客户端
练习
- 本文作者: luckyship
- 本文链接: https://luckyship.github.io/2021/05/15/2021-05-15-git-use/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!