git-代码版本管理工具
1.git 常用命令
1.1 git init:初始化仓库
mkdir project
cd project
git init
指定目录作为 git 仓库
git init project
1.2 git clone:克隆仓库
git clone [url]
1.3 git add:添加
将一个文件添加至 stage(暂存区)
# 添加某一个文件
git add [file]
# 全部添加
git add .
1.4 git status:查看状态
git status
1.5 git diff:显示变更
# 显示尚未添加到stage的文件的变更。
git diff
# 显示添加到stage的文件与当前最新版本之间的差异
git diff –staged
# 显示两个分支之间的差异
git diff [first branch] [second branch]
1.6 git commit:提交
从工作区提交到暂存区
git commit "[Type in the commit message]"
1.7 git reset:重置
情景解析:
–mixed(默认):重置位置的同时,只保留 Working Tree 工作目录的內容,但会将 Index 暂存区 和 Repository 中的內容更改和 reset 目标节点一致,因此原节点和 Reset 节点之间的【差异变更集】会放入 Working Tree 工作目录中。所以效果看起来就是原节点和 Reset 节点之间的所有差异都会放到工作目录中。
–hard:重置位置的同时,直接将 working Tree 工作目录、 index 暂存区及 repository 都重置成目标 Reset 节点的內容,所以效果看起来等同于清空暂存区和工作区。
–soft:重置位置的同时,保留 working Tree 工作目录和 index 暂存区的内容,只让 repository 中的内容和 reset 目标节点保持一致,因此原节点和 reset 节点之间的【差异变更集】会放入 index 暂存区中(Staged files)。所以效果看起来就是工作目录的内容不变,暂存区原有的内容也不变,只是原节点和 Reset 节点之间的所有差异都会放到暂存区中。
应用场景:
–hard:(1)放弃本地的所有改变,即去掉所有 add 到暂存区的文件和工作区的文件;(2) 抛弃目标节点后的所有 commit(之后所有的 commit 都不对)。
–soft:合并差异不大的 commit,使整个演进线图更清晰。
–mixed(默认):(1)与 2 类似,合并相似的 commit;(2)移除暂存区中的内容。(3)commit 提交某些错误代码,不想再修改错误再 commit(因为会留下一个错误 commit 点),可以回退到正确的 commit 点上,然后所有原节点和 reset 节点之间差异会返回工作目录,假如有个没必要的文件的话就可以直接删除了,再 commit 上去就 OK 了。
案例:
# 原节点和 Reset 节点之间的所有差异都会放到工作目录中(不会更改工作区的代码)
git reset
# 丢弃所有的历史记录,并回滚到指定的提交(会更改工作区的代码)
git reset --hard
# 主分支丢弃所有的历史记录,并回滚到指定的提交(会更改工作区)
git reset --hard origin/master
# 可以 拉取最近一次提交到版本库的文件到暂存区 并且该操作不影响工作区
git reset HEAD --
1.8 git rm:删除
删除工作目录中的文件,并将删除动作添加到 stage。
git rm [file]
1.9 git mv:移动或重命名
移动或重命名一个文件、目录、软连接
git mv oldname newname
1.10 git log:历史记录
用于显示当前分支的版本历史记录
git log
显示某个文件的版本历史记录,包括文件的重命名
git log –follow [file]
1.11 git push:发送到远程代码库
将主分支上提交的变更发送到远程代码库
git push [variable name] master
将指定分支上的提交发送到远程代码库。
git push [variable name] [branch]
将所有分支发送到远程代码库。
git push –all [variable name]
git push --all origin
# 上面命令表示,将所有本地分支都推送到origin主机。
--force :
使用–force 选项,结果导致在远程主机产生一个”非直进式”的合并(non-fast-forward merge)。
除非你很确定要这样做,否则应该尽量避免使用–force 选项
git push --force origin
删除远程分支
git push –d [branch]
git push -d origin v1.0
# 删除分支v1.0
-u 参数
git push -u origin master
git push -u origin master 执行添加了-u 参数的命令,就相当于是执行了
git push origin master 和 git branch --set-upstream master origin/master。
所以,在进行推送代码到远端分支,且之后希望持续向该远程分支推送,则可以在推送命令中添加 -u 参数,简化之后的推送命令输入。
1.12 git pull:获取远程服务器的变更
将获取远程服务器上的变更,并合并到你的工作目录。
git pull [Repository Link]
1.13 git stash:临时保存
将临时保存所有修改的文件。
git stash save
将恢复最近一次 stash(储藏)的文件。
git stash pop
将显示 stash 的所有变更。
git stash list
将丢弃最近一次 stash 的变更。
git stash drop
1.14 git branch/checkout: 分支管理
列出分支
# 当前分支
git branch
# 所有分支
git branch -av
创建分支
git branch [分支名]
# 创建分支2.0(不切换)
git branch v2.0
删除本地分支
git branch -d v2.0
# 结果:Deleted branch v2.0 (was 3d47fcd).
删除远程分支
git push -d origin v1.0
切换分支
# 切换到分支2.0,如果有远程分支v2.0,本地将新建v2.0分支,并关联远程v2.0分支
git checkout v2.0
# 本地将新建并切换到local-v2.0分支,并关联远程v2.0分支
git checkout -b local-v2.0 origin/v2.0
# 创建新的v2.0分支并切换到分支(v2.0分支必须不存在)
git checkout -b v2.0
# 结果:Switched to a new branch 'v2.0'
合并分支
git merge [分支名]
# 例:当前所在分支master,合并分支v2.0
git merge v2.0
取消合并分支
git merge --abort
1.15 git tag:标签
# 直接列出所有的标签
git tag
# 可以根据 xxxx 进行标签的筛选
git tag -l xxxx :
查看标签和它的备注:
git tag -l -n
# 运行结果
# build1 tags
# build2 tags
# test add
# test1 tags
# test2 Merge branch 'local-v2.0'
# testTag2 tastTagRemark2
查看线上代码库的标签
git ls-remote --tags
# 运行结果
# a80ed7c46fd68f973179753af76095ddd226a0a6 refs/tags/build2
# 8b9624d7f22a82f64b718d6cfcfba35a0f715fc8 refs/tags/test
# 82292aaf03a624d48df3a4ef0d24214c61a86ae3 refs/tags/testTag2
查看标签的提交信息
git show 标签名
创建轻量标签
# 直接给当前的提交版本创建一个【轻量标签】
git tag 标签名
# 例如:给当前版本一个tag "test"
git tag test
# 给指定的提交版本创建一个 【轻量标签】
git tag 标签名 提交版本
# 例如:给版本"9398f2ad"一个tag "test2"
git tag test2 9398f2ad
创建附注标签
- -a : 理解为 annotated 的首字符,表示 附注标签
- -m : 指定附注信息
git tag -a 标签名称 -m 附注信息
# 例 给当前版本一个tag "testTag1" 附注信息 "tastTagRemark"
git tag -a testTag1 -m tastTagRemark
git tag -a 标签名称 提交版本号 -m 附注信息
# 例:给版本"9398f2ad"一个tag "test2" 附注信息 "tastTagRemark2"
git tag -a testTag2 9398f2ad -m "tastTagRemark2"
删除标签
git tag -d 标签名称
# 例 删除tag "testTag1"
git tag -d testTag1
# 结果:Deleted tag 'testTag1' (was d3f0ab8)
推送到远程仓库
# 将指定的标签上传到远程仓库
git push origin 标签名称
# 将指定的标签testTag1上传到远程仓库
git push origin testTag1
# 结果:* [new tag] testTag1 -> testTag1
# 将所有不在远程仓库中的标签上传到远程仓库
git push origin --tags
# 结果:
# * [new tag] build1 -> build1
# * [new tag] build2 -> build2
# * [new tag] test2 -> test2
# * [new tag] testTag2 -> testTag2
删除远程仓库的标签
git push origin --delete 标签名称
git push origin -d 标签名称
# 删除远程标签test2
git push origin --delete test2
# 运行结果: - [deleted] test2
# 删除远程标签build1
git push origin -d build1
# 运行结果 - [deleted] build1
检出标签:
以标签指定的版本为基础版本,新建一个分支,继续其他的操作。因此 ,就是 新建分支的操作了
git checkout -b 分支名称 标签名称
2.仓库建立、导入、关联
已有文件夹或仓库
cd existing_folder
git init
git remote add origin https://codeup.aliyun.com/123456/test.git
git add .
git commit
git push -u origin master
导入代码库
git clone --bare https://git.example.com/your/project.git your_path
cd your_path
git remote set-url origin https://codeup.aliyun.com/123456/test.git
git push origin --tag && git push origin --all
代码库关联到新的仓库地址
git remote set-url origin https://codeup.aliyun.com/123456/test.git
git push
3.github ssh 配置
3.1 配置用户名和邮箱
git config --global user.name "masecho"
git config --global user.email "masecho@163.com"
3.2 生成密钥
使用 ssh-keygen 生成密钥
-t 加/解密算法
-b 秘钥长度,rsa 默认秘钥长度的为 2048
-C 注释,一般是填写用户名
执行以下命令:
ssh-keygen -t rsa -C masecho@163.com
之后显示
Generating public/private rsa key pair.
Enter file in which to save the key (/c/Users/Administrator/.ssh/id_rsa):
之后一直回车,在目录文件夹(C:/Users/Administrator/.ssh)中自动生成文件 id_rsa 与 id_rsa.pub。
3.3 复制公钥内容到 github
使用 notepad++打开 id_rsa.pub 文件,复制文件全部文本内容
进入 github 网站,登录后进入个人 setting->SSH and GPG keys,
进入 SSH keys 页面 然后 Add new,粘贴 id_rsa.pub 文件全部文本内容,保存
3.4 测试与 github 的通信
ssh -T git@github.com
多测试几次
3.5 本地使用多个 github 账号
生成第二个 github 的账号的密钥,生成文件名称为 masechozhang_id_rsa,账号为masechozhang@gmail.com
cd ~/.ssh/
ssh-keygen -t rsa -f ~/.ssh/masechozhang_id_rsa -C "masechozhang@gmail.com"
复制公钥内容到 github:setting->SSH and GPG keys(参考 3.3 复制公钥内容到 github)
~/.ssh/中创建 config 文件
vim config
文件内容如下,config
# 配置默认账号对应的ssh key
Host github.com
HostName ssh.github.com
User masecho
IdentityFile ~/.ssh/id_rsa
#配置另一个帐号
Host mz.github.com
HostName ssh.github.com
User masechozhang
IdentityFile ~/.ssh/masechozhang_id_rsa
添加密钥
#默认操作系统是不开启 ssh-agent 的,需要手动打开
ssh-agent bash
ssh-add ~/.ssh/masechozhang_id_rsa
#输出结果:
Identity added: /c/Users/Administrator/.ssh/masechozhang_id_rsa (masechozhang@gmail.com)
3.6 gitignore 不生效的情况
删除 git 本地缓存,再提交
git rm -r --cached .
4. 分支策略
分支策略:
- master 分支是整个项目的主分支
- develop 分支反映最新的开发
- feather 分支用于某个新功能的开发
- release 分支用于准备新版本的发布。
- hotfix 分支用于紧急 bug 修复
4.1 master 分支
- 所有其他分支都直接或间接源自 master。master 分支只用于产品发布,不能在上面进行工作。
4.2 develop 分支
- develop 中的代码总是可以完整编译的。
- 当 develop 中的代码进入稳定状态(修复了绝大多数 bug)准备 release 时,所有 develop 中的更改将通过 release branch 最终 merge 到 master。
- master 和 develop 分支要和远程仓库保持一致
4.3 feather 分支
- feather 分支用于某个新功能的开发,源自 develop,并最终 merge 到 develop。
- feather 分支最终要么合并到 develop 分支,要么被删除。
4.4 release 分支
- release 分支用于准备新版本的发布。源自 develop,merge 到 develop 和 master。
- release 分支仅修复小的 bug,不能添加新功能。而 develop 分支可以同时开始新功能的开发。该分支上修复的 bug 需要 merge 到 develop,并在该分支完成时 merge 到 master。此时需要给 master 打上 tag,标记这个新的 release。
4.5 hotfix 分支
- Hotfix 分支用于紧急 bug 修复,源自 master,merge 到 develop 和 master。
- 对于已经上线的产品,可能有意外的紧急 bug 需要修复。hotfix branch 可以避免修复 bug 的工作影响 develop 分支
5.git 常见问题
5.1 git merge 与 git rebase 的区别
git merge
- 使用 merge 是很好的方式,因为它是一种非破坏性的操作,对现有分支不会以任何方式被更改。
- 另一方面,这也意味着 bugFix 分支每次需要合并上游更改时,它都将产生一个额外的合并提交。
- 如果 main 提交非常活跃,这可能会严重污染你的 bugFix 分支历史记录。不过这个问题可以使用高级选项 git log 来缓解
git merge 示例:
# 创建新分支 bugFix
git branch bugFix
# 用 git checkout bugFix 命令切换到该分支
git checkout bugFix
# 提交一次
git commit -m "bugFix xxxxxx"
# 用 git checkout main 切换回 main
git checkout main
# 再提交一次
git commit -m "main xxxxxx"
# 用 git merge 把 bugFix 合并到 main
git merge bugFix
git rebase
rebase 会将整个 bugFix 分支移动到 main 分支的顶端,从而有效地整合了所有 main 分支上的提交。
但是,与 merge 提交方式不同,rebase 通过为原始分支中的每个提交创建全新的 commits 来重写项目历史记录,特点是仍然会在 bugFix 分支上形成线性提交
rebase 的主要好处是可以获得更清晰的项目历史。首先,它消除了 git merge 所需的不必要的合并提交;其次,正如你在上图中所看到的,rebase 会产生完美线性的项目历史记录,你可以在 bugFix 分支上没有任何分叉的情况下一直追寻到项目的初始提交。
当前 git status 在哪个分支上,rebase 之后的最新分支就在哪个分支上。
git rebase 示例:
# 新建并切换到 bugFix 分支
git checkout -b bugFix
# 提交一次
git commit -m "bugFix xxxxxx"
# 切换回 main 分支再提交一次
git checkout main
git commit -m "main xxxxxx"
# 再次切换到 bugFix 分支,rebase 到 main 上
git checkout bugFix
git rebase main
如何选择 git merge 和 git rebase?
- git merge 优点是分支代码合并后不破坏原分支的代码提交记录,缺点就是会产生额外的提交记录并进行两条分支的合并,
- git rebase 优点是无须新增提交记录到目标分支,rebase 后可以将对象分支的提交历史续上目标分支上,形成线性提交历史记录,进行 review 的时候更加直观
git rebase 的黄金原则:不能在一个共享的分支上进行 Git rebase 操作。
总结:
融合代码到公共分支的时使用 git merge,而不用 git rebase
融合代码到个人分支的时候使用 git rebase,可以不污染分支的提交记录,形成简洁的线性提交历史记录
5.2 HEAD 指针指向回退
# 回退一个版本
git checkout HEAD^
git checkout HEAD~1
# 回退2个版本
git checkout HEAD^^
git checkout HEAD~2
# 回退3个版本
git checkout HEAD^^^
git checkout HEAD~3
5.3 将分支转移
# 将bugFix的分支指向当前分支的后退的三个版本
git branch -f bugFix HEAD~3
# 将当前的main分支指向c6的提交版本
git branch -f main c6
5.4 回退版本 Git Reset(不保留撤销记录)
git reset 通过把分支记录回退几个提交记录来实现撤销改动。你可以将这想象成“改写历史”。 git reset 向上移动分支,原来指向的提交记录就跟从来没有提交过一样。
git checkout main
# 本地回退一个版本
git reset HEAD~1
Git 把 main 分支移回到 C1;现在我们的本地代码库根本就不知道有 C2 这个提交了。 (译者注:在 reset 后, C2 所做的变更还在,但是处于未加入暂存区状态。)
5.5 回退版本 Git revert(增加撤销的记录)
为了撤销更改并分享给别人,我们需要使用 git revert
# 回退当前版本
get revert HEAD
- 在我们要撤销的提交记录后面居然多了一个新提交!这是因为新提交记录 C2' 引入了更改
- 这些更改刚好是用来撤销 C2 这个提交的。也就是说 C2' 的状态与 C1 是相同的。
- revert 之后就可以把你的更改推送到远程仓库与别人分享啦。
示例:
revert 相当于在撤回基础上增加一条撤回的记录,如果再次当前撤回,那么相当于
比如 v1.0-change3,我撤回一次 revert HEAD, 增加记录:Revert "v1.0-change3",代码会回到 v1.0-change3 之前的状态(v1.0-change2),再次撤回 revert HEAD,增加记录:revert change3-1 Revert "Revert "v1.0-change3" 相当于回到 v1.0-change3,第二次撤回抵消了第一次撤回,但是前面的记录也会记录下来
commit fbad6c9623e69b7df180fcec6636751365862266 (HEAD -> v1.0)
Author: masecho
Date: Tue Jun 27 17:15:42 2023 +0800
revert change3-1
Revert "Revert "v1.0-change3""
This reverts commit f6cbf3a049c9b32cbd552e0b8b9e88879654f110.
commit f6cbf3a049c9b32cbd552e0b8b9e88879654f110
Author: masecho
Date: Tue Jun 27 17:14:46 2023 +0800
Revert "v1.0-change3"
This reverts commit 47122ca9981614e6e1d42fd2aed7d72d48f320db.
commit 47122ca9981614e6e1d42fd2aed7d72d48f320db
Author: masecho
Date: Tue Jun 27 17:14:13 2023 +0800
v1.0-change3
commit 01ec80d84056799e6ed41a6d0b9913e1cb6fde6e
Author: masecho
Date: Tue Jun 27 17:13:44 2023 +0800
v1.0-change2
5.6 复制分支 git cherry-pick
git cherry-pick <提交号>
- 如果你想将一些提交复制到当前所在的位置(HEAD)下面的话, Cherry-pick 是最直接的方式了
例子:
我们想将 side 分支上的工作复制到 main 分支,只需要提交记录 C2 和 C4,所以 Git 就将被它们抓过来放到当前分支下了。 就是这么简单
当前:
# 执行cherry-pick复制
git cherry-pick c2 c4
结果:
5.7 调整提交顺序 get rebase -i
例子:目前我们有五次提交,分别为 rebase-file(1-5)
我们要更改顺序为 1、2、4、5、3
commit c4abcc2dcbb785042ef7fc5df50a36c68cca78e4
Author: masecho
Date: Wed Jun 28 10:25:41 2023 +0800
rebase-file5
commit 1609eb7f6b3eb2e90f1c5f564222cad746ad9b02
Author: masecho
Date: Wed Jun 28 10:25:28 2023 +0800
rebase-file4
commit 48d15a4d051c664166822dac0a75b27c524966e5
Author: masecho
Date: Wed Jun 28 10:25:13 2023 +0800
rebase-file3
commit b4142d077dd8ceee479259c6047d01287b69af63
Author: masecho
Date: Wed Jun 28 10:24:53 2023 +0800
rebase-file2
commit b990df0ef6c86bd92641029dbb874997bf3b1e5b
Author: masecho
Date: Wed Jun 28 10:24:38 2023 +0800
rebase-file1
使用指令 git rebase -i HEAD~3 就可以更改最近的三条提交
git rebase -i HEAD~3
出现 Vi 编辑器画面 (注意这里是按照时间顺序排列,与 git log 是按照时间倒序排列相反的)
使用 DD 可以剪切,使用 P 可以粘贴
pick 48d15a4 rebase-file3
pick 1609eb7 rebase-file4
pick c4abcc2 rebase-file5
# Rebase b4142d0..907196f onto b4142d0 (5 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
# commit's log message, unless -C is used, in which case
# keep only this commit's message; -c is same as -C but
# opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# create a merge commit using the original merge commit's
# message (or the oneline, if no original merge commit was
# specified); use -c <commit> to reword the commit message
# u, update-ref <ref> = track a placeholder for the <ref> to be updated
# to this position in the new commits. The <ref> is
.git/rebase-merge/git-rebase-todo [unix] (11:09 28/06/2023)
修改成 4/5/3,(1/2/3/4/5)=>(1/2/4/5/3)
pick 1609eb7 rebase-file4
pick c4abcc2 rebase-file5
pick 48d15a4 rebase-file3
之后按"esc",输入 ":wq"就可以保存,若不想更改,输入 ":qa!",结果如下:
commit 48d15a4d051c664166822dac0a75b27c524966e5
Author: masecho
Date: Wed Jun 28 10:25:13 2023 +0800
rebase-file3
commit c4abcc2dcbb785042ef7fc5df50a36c68cca78e4
Author: masecho
Date: Wed Jun 28 10:25:41 2023 +0800
rebase-file5
commit 1609eb7f6b3eb2e90f1c5f564222cad746ad9b02
Author: masecho
Date: Wed Jun 28 10:25:28 2023 +0800
rebase-file4