使用git进行版本管理(不断更新中)

使用git进行版本管理

常识
  • 文件的几个状态:Untracked,Unmodified(已修改,此时文件在工作目录),Modified(已暂存,此时文件在暂存区),Staged(已提交,此时文件在版本仓库)
  • 在终端使用git 命令,需要帮助可以直接在命令后面加 -h,便可以查看命令的使用说明
文档状态:基本内容完成,处于细节调整中。

一、git基础操作
开始使用
git的基础配置
git的基础配置分为三个作用域
  • local:只对当前的长裤有效
  • global:对登录用户的所有仓库有效
  • system:对系统的所有用户有效
config的优先级:local>global>system
git config --global user.name 'name' git config --global user.email 'email@email'# 显示git config的配置 git config --list --local git config --list --global git config --list --systemgit config --local user.name # 仅查看user.name# 设置,缺省等同于local git config --local git config --global git config --system# 清除 git config --unset --local user.name git config --unset --global user.name git config --unset --system user.name# git编辑器默认使用shell环境变量$EDITOR所指定的软件。一般vim/emacs,可以使用下面命令将终端下的默认编辑器更改为vim, git config --global core.editor vim


初始化git仓库
# 已有项目代码,进入到项目的根目录,在当前目录下创建git仓库 git init# 无项目代码 cd 某个文件夹 git init project # 在当前目录下创建和项目名称同名的文件夹 cd project


忽略某些文件
在项目内,有些文件,比如常见的第三方依赖,或者是构建后生成的文件,他们可以通过安装或者构建得到,对于这些文件,我们通常不将其列入我们的版本仓库,这可以通过在项目的根目录下添加.gitignore文件来实现。文件内容如下。
doc 将不会管理doc文件夹内的所有内容,也不管doc文件 doc/ 只不管doc文件夹内的文件# 对于前端项目通常会添加如下的内容 .DS_Store node_modules/ /dist/ npm-debug.log* yarn-debug.log* yarn-error.log* /test/unit/coverage/ /test/e2e/reports/ selenium-debug.log

我们在使用某些IDE时通常会有插件可以帮助我们更加快捷的添加gitignore。比如Jetbrains就可以通过插件很方便的添加gitignore

git别名
git 为了方便我们的使用,可以对常用的命令起别名,从而提升终端的使用效率
git config --global alias.co checkout git config --global alias.unstage 'reset HEAD --' git config --global alias.visual '!gitk' 执行外部命令 + !


Git的工作流程
  1. 在目录中添加、修改文件
  2. 将需要进行版本管理的文件放入暂存区域
  3. 将暂存区域的文件提交到Git仓库

将文件添加到暂存区
git add . # 跟踪当前目录下的所有文件 git add fileA fileB #跟踪fileA和fileB文件 git add -u # 将所有已跟踪文件的变更添加到暂存区


将暂存区内容提交至git仓库
提交得commit message要尽可能得有意义,便于我们了解此次变更做了什么。否则这会其他人造成困扰,也会给我们得某些操作造成困扰,比如无法通过git reflog,知道我们得每个git操作具体做了什么
git commitgit commit -m 'message'git commit -a -m 'message' 或 git commit -am 'message' 对于在工作区内新增加还未追踪的文件不生效。git commit --amend //追加提交,在不增加新的commit-id的情况下,将新修改的代码追加到前一次commit-id中git commit --help


打标签
git 打标签,针对的是一个commit。打标签一般是伴随着发版进行的,通过git标签,我们可以更加方便的进行版本查看和回退等操作,也是非常重要的一个环节。
git tag //列出已有标签 git tag -l 'v1.8.5'//使用特定模板进行查找标签分为两类:轻量标签和附注标签git tag -a v1.4 -m 'message'git show v1.2 可以看到标签信息与对应的提交信息git show [hash]git tag v1.4//轻量标签git tag -a v1.2 9fceb02//针对于某个commit打标签****************** 共享, ******************** git push不会将tag推送到远程仓库 git push origin v1.5 // 标签必须显示推送git psuh origin --tags // 推送所有*******************检出******************** git checkout [tag] // 检出某个tag // 会处于分离头指针状态,,此时的提交不属于任何的分支,如需要修改需要新建分支git checkout -b version2 v2.0.0// 在特定标签上创建一个新分支****************** 删除tag ********************** git tag -d v1.4 git push origin :refs/tags/v.14


分支
分支对于git来说是非常重要的一个概念,我们通常会在主分支上新建新的分支进行自己的开发或者是bug修改。然后等待开发完成并验证后,在通过合并分支,将我们的新功能或者是bug修改合并到主版本库
git branch branchNamegit branch -v #看本地的分支git log --oneline --decorate//查看各个分支所指的对象。git checkout branchNamegit checkout -b branchNamegit log --oneline --decorate --graph --all//输出提交历史,各个分支的指向及项目分支匹配情况。git分支实质上是包含所指对象校验和(长度为40的SHA-1值字符串)的文件。git branch -d branchNamegit branch -D branchNamegit merge branchName分支合并的结果做新的快照,自动创建一个提交指向这个新的快照。分支合并自动选取一个提交作为共同祖先,以此作为合并的基础分支冲突: 1.遇到冲突,Git会暂停下来,合并时可以使用git status 查看因为冲突未合并的文件,使用git merge --abort强制合并,使用git add fileName标记已解决的冲突。git branch --merged 或 git branch --no-merged 查看已经合并或者尚未合并的分支。没有合并过的分支使用git branch -d branchName 删除会失败。//修改分支名字,远程的要删除重新推 git branch -m oldName newName


分支开发工作流

远程分支
远程引用是对远程仓库的引用(指针),包含分支标签等等。git ls-remote显示地获取远程引用的完整列表,通过git remote show(remote) 获得远程分支的更多信息
git branch --set-upstream branch-name origin/branch-name将本地分支与远程分支关联


查看版本仓库
查看当前状态
查看当前git仓库的状态,比如说查看我们对工作区和贮存区做了什么更改,或者是我们当前处于哪一个分支都可以使用此命令。
git status git status --short 或 git status -s //获得紧凑的格式输出// ?? 新添加未跟踪的文件。 //A 新添加到暂存区的文件 //M右边,修改了没有放到暂存 //M左边,文件被修改了并放入暂存区。


比较版本间差异
通过git的git diff命令,我们可以比较任意文件在两个commit之间的差异。
比较暂存区域和工作目录:git diff j f b d u 键控制翻页 g G第一行,最后一行 3g 跳到第三行 /或者?+关键词 上到下,下到上搜索,高亮的是匹配的 n下一个 N 上一个 输入h帮助文档 q退出
git diff# 工作区和暂存区。git diff --cached / git diff staged# 暂存区和版本库git diff -- 文件名 # 具体的文件差别可以多个文件git diff masterA materB# 比较任意两个分支git diff [old-commit] [new-commit-id] -- fileName# git比较任意两个commit之间的差异


查看提交记录 git log
我们可以使用git log命令来查看我们对版本仓库的历史操作信息。
git log# 按照时间列出所有更新,最新的在上面,列出SHA-1校验和名字邮箱,提交时间,说明,只展示当前分支 git log -p -2# 用来显示每次提交的内容差异,2表示仅显示最近两次提交。 git log -n2# 仅显示最近两次提交。 git log --stat# 附带总结信息,列出每次被修改的文件 git log --pretty=oneline# 在同一行显示 git log --oneline # 同一行显示 git log --all # 展示所有分支的版本历史 git log --graph # 图形化的方式展示 git log branchName # 之查看某个分支,有all的话这个不生效git log --pretty=format:"%h - %an, %ar : %s" git log --since=2.weeks//最近两周 --author指定作者--grep搜索提交说明中的关键字如果要的到同时满足这两个选项的搜索条件的提交,就要用--all-match-s 列出添加或移除了某些字符串的提交。例如 git log -Sfunction_name--path指定路径git log --pretty="%h - %s" --author=gitster --since="2008-10-01" \ --before="2008-11-01" --no-merges -- t/git log --oneline --decorate 查看各个分支当前所指向的对象 git log --pretty=oneline [fileName]git log --abbrev-commit'显示最简短的唯一值'git help --web log # 通过浏览器查看所有gitk# 打开图形化界面


文件操作
对文件重命名
将readme重命名为readme.md
# 方法1 mv readme readme.md # 直接重命名 git add readme.md# 添加重命名后的文件 git rm readme# 删除原来文件# 方法2 git命令 git mv readme readme.md #使用git mv变更文件名



重命名文件
git mv file_from file_to等同于 mv file_from file_to git rmfile_from git add file_to


删除文件
git rm 文件名。删除文件并提交,使文件不再被追踪。git rm 文件名 等同于 rm 文件名+git add .如果删除之前修改过并放入暂存区。需要-f强行删除git rm --cached 文件名从暂存区删除,但保留在工作区


贮藏代码 当我们对工作区和贮存区的代码进行了更改之后,有额外的任务插入,我们需要将现在工作区和贮存区的内容暂时的存储起来,此时便用到了 git stash

git stash
git stash git stash list git stash apply // 已暂存的文件不会被重新暂存 git stash apply --index // 重新暂存已暂存的文件 git stash apply stash@{2} git stash dropstash@{2}//删除储藏 git stash pop// 重新应用并删除 git stash branch branchName //从最新储藏新建分支,成功后会删掉该储藏 git stash save noteContent // 等同于git stash,但是可以增加注释 git stash clear //清理所有 git stash show stash@{2} //查看stash和当前的差异


回退与撤销
撤销操作
git commit --amend//第二次提交代替第一次提交的结果git reset HEAD ...// 取消暂存。(不加选项只会修改暂存区内容,所以并不危险)git checkout --


暂存区恢复到头指针的状态
不保留暂存区的所有内容,将其恢复到跟head一样。
  • 首先要将工作区内容 git stash
  • git reset HEAD 将暂存区的恢复到了工作区

将暂存区的恢复到工作区
取消工作区的变更
git checkout -- fileName

删除历史提交中近几个commit
git reset --hard hash

代码回退
  • 将暂存区域恢复到之前状态:git reset HEAD 文件名,不指定为所有
  • 将暂存区的旧版本呢覆盖回:git checkout -- 文件名
  • 回到过去:
    • 仓库Repository和暂存区Stage之间,commit reset
    • 工作空间Working和暂存区Stage之间,add checkout
    • git reset HEAD~ ~指上一个
    • git rest --mixed(默认的不用写) HEAD~
      • 移动HEAD指向,将其指向上一个快照
      • 将HEAD移动后指向的快照回滚到暂存区
    • git rest --soft HEAD~
      • 移动HEAD指向,将其指向上一个快照(撤销一次错误的提交)
    • git rest --hard HEAD~ (存在危险性)
      • 移动HEAD指向,将其指向上一个快照
      • 将HEAD移动后指向的快照回滚到暂存区
      • 将暂存区的文件还原到工作目录
    1. 移动HEAD的指向(--soft)
    2. 将快照混滚到暂存区域([--mixed], 默认)
    3. 将暂存区域还原到工作目录(--hard)
    • 回滚指定快照,指定前几个:git reset id号
    • 回滚快照里个别文件
      • git reset 快照版本 文件名/路径
      • git reset 快照版本的ID号

远程仓库
git remote// 列出远程仓库简写git remote -v//展示简写和对应的URLgit remote addgit fetch [remote-name]//从远程仓库获取数据,执行完成,会拥有远程仓库中所有分支的引用,可以随时合并查看。只是将数据拉取到本地仓库,不会合并或者修改。git pull 会自动甚至本地的master跟踪克隆的远程仓库的mastergit push origin master//写入权限,之前别人没有推送过。git remote show origin 查看某个远程仓库的信息git remote rename oldname newname//修改远程仓库名字,也会修改你的远程分支的名字git remote rm 仓库名git clone -b [branchName] [branchName]


多人协作 多人协作,不能强制提交,不能变基。

多人修改同一个文件的文件名
会报冲突,手动解决
git rm 源文件名
git add 需要的文件名
git rm 分期的文件名

有人把文件名变更,其他人基于原来的文件名变更了文件内容。
git会自动合并。git可以很好的处理这种情况,其他的版本控制不一定能良好处理。

高级使用
git chery-pick
git chery-pick可以将某个commit复制到当前的分支。chery-pick后,处于对记录历史的考虑,Auther是这个commit原来的提交人,但commiter是自己。
举例子:将branch1 的 commit1 提交 应用到 branch2 分支上来
实现步骤:
  1. 使用git log 查看需要被应用到新分支的commit的 hash是多少。
  2. 切换到branch2 git chery-pick [commit1hash]即可自动提交
chery-pick的参数:
  • 在git chery-pick后加上-n可以避免自动提交。
  • 在git chery-pick后加上-e可以编辑commit信息。
  • 与git rebase类似,当遇到冲突时有以下处理办法, git cherry-pick --continue,git cherry-pick --abort,git cherry-pick --quit

将commit之间得差异差异应用到新的提交
场景:branchA和branchB的差异应用到branchC
实现步骤:
  1. git diff后增加 > patch
  2. 切换到branchC
  3. git apply patch
  4. 注意会在当前目录下生成patch文件,需要手动删除等操作

git钩子
通过git钩子,可以使得我们在执行git得某些操作时,触发一些脚本,比如在提交时校验我们的commit message是否符合要求,才我们推送代码到远程前,运行我们代码中的单元测试确保代码质量等。

git忽略commit钩子
  • git commit --no-verify ,这可以使我们得提交不触发commit得执行。

使用git钩子校验commit message
git reflog
git reflog 主要记录我们对于git得操作,通过它可以查找到所有分支的所有操作记录,包括删除的以及reset的内容!当我们因为不恰当得git操作,不小心将我们得代码删除了,我们就可以通过git reflog找回我们得代码。git log存储在本地。

不小心git reset --hard HEAD^找回 【使用git进行版本管理(不断更新中)】不小心将我们得代码回退到了上个版本,找回丢失得代码。
实现步骤:
  1. 使用git reflog找到我们不小心删除得commit得commit hash。
  2. 使用chery-pick 找回即可

在分离头指针状态下进行了提交切换分支之后丢失代码得找回 实现步骤与 不小心git reset --hard HEAD^找回 方法相同

更改git提交历史
通过git rebase,我们可以很容易的对我们的提交历史做更改。对提交的历史进行修改,可能会造成代码的冲突,我们需要解决冲突。
更改git的提交历史是非常****危险****的操作,更改后的分支无法直接推送到远程仓库,****必须强制推送****,如果分支涉及到****多人协作,****需要特别注意,避免产生不必要的麻烦****。

通过变基来整合不同分支的修改 我们已master分支为基准开发新的功能,首先我们为了开发新的功能切出了新的分支feature1,经过一周时间,我们开发完毕。在这一周之内,其他同事也在进行正常的开发并且上线完成,合入到了master分支。此时我们需要将这一周之内其他同事对于master的更改应用到自己的feature1分支上,此时便可以通过合并分支和变基来实现,通过变基可以使我们的git提交历史趋与一条直线。他与合并分支的明显区别就是,合并分支,会使得我们的多次commit与这周内master变更的commit依照时间混合在一起,使用变基则会使得我们得commit顺序位于master上得这些提交之后。变基操作可能会产生冲突。
# 使用合并分支 git merge master# 使用变基 git rebase master


修改commit的顺序
  1. git rebase -i [commit-hash]
  2. 此时会出现一个编辑窗口,我们直接在编辑窗口内移动coomit的顺序之后保存即可。
常用的vim快捷键:复制:yy, 粘贴p,回退 u ,保存wq

借助于git rebase,拆分commit https://blog.csdn.net/weixin_33736832/article/details/87960663
实现步骤:
  1. git rebase -i [commit-hash]
  2. 此时会出现一个编辑器窗口,在编辑器内出现的是我们所有的commit,将要拆分的commit 前面状态改为e,保存编辑的内容。
  3. git rebse会停留在需要拆分的commit。
  4. 此时使用 git reset HEAD^ 撤销需要拆分的commit。
  5. 查看当前的status,此时可以按照我们的需要,添加多次提交。
  6. 我们更改玩提交后,git rebase --continue。此时我们已经成功修改了提交记录

二、Git工具
选择修订版本
分支引用
git show [branchName]

git show SHA-1
git rev-parse [branchName] 查看git当前处于什么状态。

引用日志
git reflog 查看引用日志,每当HEAD所指向的位置发生了变化,git就会将这个信息存储到引用日志。
git show HEAD@{5}
git show master@{yesterday} 查看昨天这个分支指向了哪次提交。只对还在引用日志里的数据有用。
git log -g 查看类似于 git log 输出格式的引用日志信息
分支引用只存在于本地仓库,新克隆则引用日志是空的

祖先引用
使用HEAD^来查看上一次提交

HEAD^2 D当前提交的第二次父
HEAD~ 指向第一次父提交

HEAD~2 第一父提交的第一父提交
这两种可以组合

提交区间
git log master..experiment查看在experiment分支中存在而不在master分支中存在的提交。 git log origin/master..HEAD查看即将推送到远端的内容。

留空一边git默认其为HEAD

多点
git log refA..refB git log ^refA refB git log refB --not refA

与双点语法区别。
git log refA refB ^refC git log refA refB --not refC


三点
选出两个引用中只有一个包含的提交

git log master...experiment

增加参数 git log --left-right master...experiment

交互式暂存
交互式暂存,将文件的特定部分组合成提交,修改一组文件后,希望改动可以放到若干个提交而不要混杂在一起。这可以确保提交是逻辑上独立的变更集

git add -i

git add --interactive
在命令区域,可以暂存文件,取消暂存文件,暂存文件的一部分,添加未被追踪的文件,查看暂存区内容区别。

暂存与取消暂存文件



三、git基础知识
.git里面都有什么
  • HEAD文件存储当前的分支,直接编辑与切换分支是同样的效果
  • config文件存储,针对于本文件的config
  • refs文件夹 heads对应分支 tags head内的文件存储的是hash值, tags内的hash,hash值指的是 commit
  • objects 内的文件夹与文件夹内的文件组成hash值,使用git cat-file 查看是tree。 使用命令查看数的内容,是一个文件对象,通过git cat-file -p hsdh查看就是文件的内容
git cat-file -t hash#命令显示版本库对象的内容、类型及大小信息。 看内容用-p

commit tree blob是三个核心的对象。
只要任何文件的文件内容相同,就是唯一的blob

commit tree blob 三者关系 [图片上传失败...(image-acb2c9-1583609442636)]
一个commit对应一颗树,树代表了commit对应的视图,视图里面存储快照,快照里放了当前commit对应的本项目仓库的所有文件夹以及文件的快照。blob与文件名无关系。
举例:
空仓库,下有doc/readme
git add 将文件加入暂存区,那么git就会在.git/objects下创建对应文件的blob。比如 .git/objects/2d/832d90044c。使用git cat-file -t 2d832d90044c 查看可以发现类型是blob,通过git cat-file - p t2d832d90044c,可以查看到,文件的具体内容
git commit 提交后,那么git就会在.git/objects下会有4个文件.
  • 一个对象:tree 内容是doc
  • 一个对象:blob readme的文件内容
  • 一个对象:tree 里面readme文件的blob
  • 一个对象: commit



使用git进行版本管理(不断更新中)
文章图片
git图2.png

分离头指针(detached HEAD) 变更没有基于某个branch去做,所以进行分支切换时,在分离头指针之上产生的commit,可能会被git当作垃圾清理掉,如果认为变更时重要的那么,一定要将变更与分支绑到一起。
git checkout [commitHash]
本质上是工作在没有分支的状态下,此时可以做开发,提交(通过git log可以明显的看到HEAD没有与分支关联)。如果切换到新的分支,那些没有与分支关联的变更可能会被git当作垃圾清理掉。要对分支做变更。git checkout -b new-branch-name。
在分离头指针时切换分支git会提示是否要为已经提交的commit建branch, git branch
可以利用这一特性做尝试,当丢弃时,直接切换到别的分支即可。

特殊标识符HEAD HEAD不仅可以指代新分支最后一次提交,同时HEAD还可以不跟分支挂钩,处于分离头指针状态(指导某个commit上),如果新建/切换branch,HEAD指针指向新的分支。无论处于什么状态,HEAD最终会落脚在commit。
HEAD可以指代commit。
git diff HEAD HEAD^ 比较这个commit和其父commit的提交。
HEAD^^ 等同于 HEAD~2

git的备份 可以备份到本地的其他地方。
协议和智能协议
直观区别:哑协议传输进度不不可?见;智能协议传输可?见。
传输速度:智能协议?比哑协议传输速度快。
git clone --bare /User//.git ya.git 哑协议
git clone --bare file:///User//.git zhineng.git 智能协议

git remote add zhineg file:///User/**/.git
git push 进行远端备份



四、使用问题归纳
本地初始化git仓库并添加远程仓库
git init git remote add origin <远程仓库地址> git add . git commit -m "注释" git pull --rebase origin master git push origin master



删除远程分支后本地还可以通过 git branch -a看到 解决
https://www.cnblogs.com/taohuaya/p/10912245.html
git branch -a#查看所有本地分支和远程分支 git remote show origin#查看remote地址,远程分支,还有本地分支与之相对应的关系等 git remote prune origin [branch] # 根据提示进行此操作,删除本地分支的branch,这样就可以在本地删除远程不存在的分支


git忽略已经提交的文件(.gitignore文件无效) 解决链接:https://www.jianshu.com/p/e5b13480479b
方案一
git rm [ignoreFileName] git commit -am [commit-message]#删除不需要的文件

.gitignore文件中添加忽略规则,提交.gitignore文件
git push [remote]

方案二
git rm -r --cachced build/*# 都不需要可以不跟文件名 git add . git commit -m 'commit ' git push

针对已经commit过且有改动的文件 (因为rm的是cached列表中的文件, cached列表即修改列表)
最好在创建 git仓库的同时就创建.gitignore文件

merge两个不相干的分支 git merge -allow-unrelated-histories master orogin/master

五、Git可视化软件推荐
  • sourchTree(Mac和windows)
  • fork(Mac和windows)

六、Git学习资源推荐
  • git命令练习网页版,游戏的形式:https://learngitbranching.js.org
  • Git飞行规则(Flight Rules):https://github.com/k88hudson/git-flight-rules
  • 码云git资料(非常推荐,特别全面):https://gitee.com/all-about-git
  • 极客时间的《玩转Git三剑客》,主讲苏玲(携程代码平台负责人)

    推荐阅读