Git使用小结

发布时间 2023-07-19 11:19:35作者: 浩天之家

本文总结在工作中用到的Git相关内容,可分为基础概念、配置、本地开发、远程仓库等四个部分。

基础概念

Git将待管理数据当做一个整体,每执行一次 git commit,都是对代码仓库整体做一次完整备份。
Git 对每份文件都会计算校验和,用来校验和引用。有一个HEAD指针,始终指向当前所在分支。
每一次 clone 会将远程仓库中的每个文件的每个版本都拉取下来。

Git有工作区、暂存区、本地仓库、远程仓库四个概念,被管理的文件是从前一个区逐个移到后一个区,Git提供各种命令来支持这些移动操作。注意,提交操作的对象始终是暂存区

配置

Git的配置,从上到下分为系统级、用户级和仓库级,可通过如下命令查看:

	git config --system <-- 系统级别的配置  对应 /etc/gitconfig
	git config --global <-- 当前用户的配置  对应 ~/.gitconfig
	git config --local  <-- 当前仓库的配置  对应 .git/config

	git config --list --global       <-- 查看当前git配置

除了上述基本配置,还可以配置一些 Git alias 命令,方便日常使用。在这里,不建议配置太多,下图为笔者目前的配置

image.png

最常用的是 git stgit last
上图中的 pull.rebase = true,表示使用rebase来替换merge操作。rebase.autoStash = true,表示在rebase时,自动将当前修改stash,合并完成后再恢复当前修改。这两个设置建议配合起来使用。

命令行的Git在查看大量内容时体验不好,对于查看改动/日志、删除文件、文件改名等操作,使用 TortioseGit 图形化工具更合适。

Git仓库的忽略文件列表 .gitignore 是逐步完善的,将动态生成的、无需关心的文件排除,可提高变动查看效率。

可使用 git check-ignore -v filename 查找文件是否在忽略列表中,如果有内容,则表示已纳入忽略列表。

常见问题

本地在commitpush,发现 push 时,会提示远程仓库有更新,要先 pull,执行完 pull 后,日志记录中会多除 Merge branch 的提交节点。
这是因为git pull的默认操作是 git fetch(拉取数据到本地) 和 git merge(合并数据) 的组合。在merge时,会生成合并节点提交。
解决方案: 将 pull 操作中的合并操作,改为 rebase 。使用 git config --global pull.rebase true 该命令。

本地开发

本地开发就很简单,修改后add,将一次目标相关的文件都add后,可以commit了,为了减少冲突,在commit之前,一般先执行pull,同步远程更新后,再push

查看本地原始版本 与 本地修改后版本的区别, 使用 git diff

查看本地原始版本 与 本地修改后版本并add的区别, 使用 git diff --staged

addcommit合并在一条指令中,可执行 git commit -am "XXXX"。注意,这个操作不会对未add的文件生效。

日志查看

建议用 TortioseGit 来查看日志,直观且效率高。

如果某次改动较少,可用 git last 找最后几次提交 ,配合 git show commitId[:filename] 来查看某次特定提交的文件更改。

git diff只查看文件改动的差异,git show在查看文件改动的基础上,增加显示提交注释信息。

日志查看命令:

	git diff branch1 branch2 --stat  显示差异的统计部分
	git diff branch1..branch2 查看 branch2 中比 branch1 中多提交了哪些内容
	
	git log featureA..origin/featureA  查看从 featureA 开始到 origin/featureA 的提交,不包括featureA的提交
	                                   也可以理解为在 origin/featureA 分支中,而不在 featureA 分支中的提交。
	git log -S ZLIB_BUF_MAX --oneline 在提交中查找 ZLIB_BUF_MAX 的新增、修改、删除等提交操作    
	git log --grep XXXX 支持在日志中搜索关键字 

历史修改查看,建议直接使用 TortioseGitBlame功能,对应 Git 命令是git blame -L 69,82 fileName 查看某个文件某行的历史修改记录

处理提交记录

  • 修改提交注释

    参见 修改commit注释 ,核心为 git commit --amend 指令。
    若要将改动后的提交注释更新到远程仓库,push 时要加上 --force

  • 修改提交记录
    假设当前的提交记录是 A --> B --> C --> D , 此时想要删除 B 的提交,可以这样
    方法一:
    git reset A --hard 先回到A状态
    git cherry-pick C D 再将C和D应用到A上

      如果待处理的提交记录较多,可用 git rebase -i A, 此命令以A状态为基准,将A之后的commit,按时间熟悉,从上到下,依次列出来。只需要将 **不需要的提交** 前的 pick 改为 drop,保存退出,解决冲突后,执行 git rebase --continue 就能达到目的。
    

    方法二:
    git revert -n B
    处理完冲突后,执行 git add fileName 标记解决冲突
    然后执行 git revert --continue 继续回滚流程
    git commit -m "回滚B次修改"

  • 重返未来:使用 git reflog 查看命令历史,以便确定要回到未来的哪个版本。

分支管理

分支合并有三种方法,mergerebasecherry-pick

  1. 当需要整合其他分支的全部改动到当前分支,并且将整合操作当做一次提交,用 merge
  2. 当需要整合其他分支的全部改动到当前分支,整合操作不充当一次提交,用 rebase
  3. 当需要整合其他分支的部分改动到当前分支,整合操作不充当一次提交,用 cherry-pick

以整合 experiment 分支改动到 master 为例,介绍各自操作流程:

  • merge
	git checkout master	 <-- 切换到 master 分支
    git merge experiment	<-- 将 experiment 分支的改动全部应用到master分支,并将整合操作当做一次提交(如果在merge前,master分支没有提交,则不会生成整合节点)
  • rebase
	git checkout experiment		<-- 切换到 experiment 分支 
    git rebase master 			<-  将当前分支的改动,应用到 master 分支
    如有冲突,解决冲突后执行 git add 将冲突标记为解决
	解决完所有冲突后,执行 git rebase --continue

	git checkout master  		<-- 回到 master 分支
    git merge experiment  		<-- 进行一次快速合并

使用变基的好处在于,尽管开发工作是在多分支上并行开发,但从提交记录上看是串行的,提交记录没有分叉。

  • cherry-pick
    git checkout experiment
    git log   					<-- 记住需要迁移的commit-id
    git checkout master
	git cherry-pick commit-id   <-- 将需要迁移的commit-id合并到master
	合并过程中会遇到冲突
	方案1:用户解决冲突后,将修改后的文件加入暂存区,然后使用 git cherry-pick --continue,继续合并流程
	方案2:放弃合并,回到操作前的样子 git cherry-pick --abort
	方案3:退出,回不到操作前的样子 git cherry-pick --quit

新建并切换分支: git checkout -b featureA
删除本地分支: git branch -d 本地分支名
删除远程分支 git push origin --delete 远程分支名

修改暂存

  1. git stash 暂存已add,但还没有commit的修改
  2. git stash list 查看已暂存的修改
  3. git stash clear 清除已暂存的修改
  4. git stash apply --index 将最近暂存的修改重新应用,恢复到原状。
  5. git stash apply stash_id 可恢复旧的暂存数据
  6. git stash drop stash_id 删除指定stash_id的数据
  7. git stash show -p stash_id 查看某次stash的内容

使用注意:

  1. 暂存数据可在不同分支之间使用,需要手动清除。
  2. 暂存操作最好只保留一份,用完及时清理,同时存在多个暂存,很容易搞混,出错。

远程仓库

查看远程仓库的详细信息: git remove -v

添加远程仓库: git remote add <shortname> <url> , 添加指定远程仓库,并绑定一个简称,后续可用该简称来代替远程仓库地址。

在本地工作了一段时间后,如果远程仓库有更新,本地如何同步?

假设本地为 master 分支,远程为 origin/master 分支。

  1. 执行 git fetch 获取指定远程仓库的所有更新,此时本地不会有远程分支的可编辑副本。
  2. 执行 rebase 来将远程分支内容合并到当前分支
    也可以 git checkout --track origin/serverfix 自动新建本地同名分支并且跟踪远程serverfix分支

git push 远程仓库简称 本地分支名:远程分支名, 如果本地分支和远程分支同名,则可以省略冒号。

将本地分支关联到已存在的远程分支上:
git branch --set-upstream-to=origin/远程分支名 本地分支名

将本地分支关联到不存在远程分支上:
git push -u origin branch     

查看不同分支的上游: git branch -vv 在每个分支名称后面即可看到对应上游的简称。

开源项目协作

// 1. 获取开源项目,并在本地新建分支修改
git clone <third_repo_url> 获取开源项目仓库
git checkout -b featureA  在本地创建 featureA 分支
work...
git commit

// 2. 在 Github 上 fork third_repo_url,得到自己的远程仓库地址,my_third_repo_url
git remote add myfork <my_third_repo_url>
git push -u myfork featureA   将 featureA 分支推送到自己的远程仓库上,形成新的远程分支。
                              这样做的好处是,如果工作不被接受,master分支不会受到影响。

// 3. 在 Github 上,向原项目作者发起 Pull Request 请求。
// 开源项目提交的作者是实际做出修改的人,提交者时将此项工作提交到仓库的人。

工程实践经验

在一个大工程中,可能同时有很多修改,有的是改Bug,有的是调试日志,有的是新需求。在Git标准工作流中,会将这些改动按照分类推入到不同分支,等各分支完成后,再合并会主分支,这看起来很好,但是,它没考虑一个问题,就是切换分支对项目构建的影响。甚至从A分支切换到B分支,再切回A分支,会触发工程的编译,重编译范围与改动内容息息相关。对于大项目来说,工程重编译时间,少则十来分钟,多则半个小时到一个小时,这种切换带来的重编译耗时太大,即使用上 stash,也会触发相关文件的重编译,在笔者当前的工作场景下,不是很合适。

因此,在实际工作中,需求开发和改Bug都在个分支进行,按照每次提交最小功能原则,逐个将改动先add,等到攒够最小提交模块后,再commit。其他那些改动,比如打开调试、对配置文件的测试更改,不管是需求开发还是bug修复,都是需要的,保留在一起即可。

在本地建一个GitDemo目录用于练习、验证Git命令。

**Git GUI **的 bash,支持多行输入,只需要在每一行后加 ** 就行。

注释规范

第一行以精简文字描述描述变更,接着是一个空白行,再接着是一个详细解释,即改动的动机和它的实现与之前行为的对比。

下面是在网上摘抄的提交规范:

日志提交注释标准规范:

<type>(<scope>): <subject>   <-- 必须有  type 和 subject,scope可选
// 空一行
<body>                       <-- 可选
// 空一行
<footer>                     <-- 可选

type: 说明提交类型,有7个标识:
    feat:增加新功能
    fix:修补Bug
    
    docs:完善文档
    style:格式修改,不影响代码运行
    refactor:重构
    test:增加测试
    chore:构建过程或辅助工具变动

scope:说明提交影响范围
subject:提交目的简短描述,动词开头,结尾不要句号。
body:对本次提交的详细描述,可分多行。
     如果当前的commit针对某个issue,可执行 Closes #234 来关闭该issue 

总结

本文梳理Git在配置、本地开发、远程仓库等场景上的常用流程,并给出自己的一些实践经验,以备后续查询。