MENU

版本控制工具入门——GIT

2019 年 07 月 18 日 • 阅读: 8108 • 版本控制

GIT 与 SVN 的区别展开目录

  • SVN 服务器
  • ↗ ↑ ↖
  • / | \
  • / | \
  • / | \
  • ↙ ↓ ↘
  • SVN 客户端 SVN 客户端 SVN 客户端

SVN 是 集中式管理版本库 位于 SVN 服务器 上,优点是便于管理员掌控 开发进度,也容易给每个开发人员 授权。缺点是,服务器可能发生 单点故障,并且 容错性较差

  • 共享版本库
  • ——————————————————————
  • / / ↗ \ \ ↖
  • / / / \ \ \
  • / / / \ \ \
  • / / Push Clone\ \
  • / Pull / \ Pull \
  • Clone / / \ \ Push
  • ↙ ↙ / ↘ ↘ \
  • 开发人员 —— 开发人员 ——
  • ↑ | ↑ |
  • | | | |
  • ——————Commit ——————Commit

GIT 是 分布式版本控制系统,没有中央服务器,每个开发人员都 拥有完整的版本库,开发时无需联网,修改完毕后再提交给 共享版本库 即可。

简单来说,GIT 拥有 本地仓库,而 SVN 必须连接到远程仓库修改代码。

GIT 版本控制流程图展开目录

  • ———————————————Pull(Fetch + Merge)—————————————
  • | ↓
  • 远程仓库 ——Clone——→ 本地仓库 ————Checkout——→ 工作区
  • Remote ←——Push—— Repository Workspace
  • ↑ 暂存区 |
  • Commit——————— Index ←——————Add
  • Stage

GIT 常用命令详解展开目录

GIT 配置展开目录

同时操作 Github 和公司私有仓库需要配置不同的邮箱和私钥;Github 配置代理才可高速访问,公司不需要。以上需求都可通过 git config 预先配置。该命令有三个作用域选项,--system--global--local,分别用来对系统,全局和项目局部进行配置,优先级由低到高,默认 --local。除了使用命令,也可直接编辑配置文件,--global 对应 $HOME/.gitconfig--local 对应项目工作目录下的 .git/config

  • # 查看所有配置
  • git config --list

用户和密钥配置展开目录

配置密钥可避免每次提交输入密码。

  • # 生成多个密钥,-t(type),-C(comment),-f(file)
  • ssh-keygen -t rsa -C "admin@gmail.com" -f ~/.ssh/id_rsa_github
  • ssh-keygen -t rsa -C "admin@163.com" -f ~/.ssh/id_rsa_gitlab
  • # 将加载密钥脚本添加到 bash 启动文件
  • cat >> ~/.bashrc <<"EOF"
  • # 启动 ssh-agent 管理 ssh session
  • eval `ssh-agent -s` > /dev/null 2>&1
  • keys=(`ls ~/.ssh/*.pub | sed 's/.pub//g' | xargs`)
  • for key in ${keys[@]}
  • do
  • ssh-add "${key}" > /dev/null 2>&1
  • done
  • EOF
  • cat >> ~/.bash_logout <<"EOF"
  • eval $(ps -ef | grep ssh-agent | grep -v grep | awk '{ print "kill "$2 }')
  • EOF
  • # 重启 bash
  • /usr/bin/env bash
  • ssh -T git@github.com
  • # 向全局配置文件添加不同 git 站点
  • cat >> $HOME/.ssh/config <<'EOF'
  • # gitlab
  • Host git.iboxpay.com
  • HostName git.iboxpay.com
  • PreferredAuthentications publickey
  • IdentityFile ~/.ssh/id_rsa_gitlab
  • User admin
  • # github
  • Host github.com
  • HostName github.com
  • PreferredAuthentications publickey
  • IdentityFile ~/.ssh/id_rsa_github
  • User admin
  • EOF
  • # 切换到每个项目目录,当独设置用户名和邮箱
  • git config user.email "admin@gmail.com"
  • git config user.name "admin"
  • # 取消设置
  • git config --unset user.name
  • git config --unset user.email

代理配置展开目录

为 Github 设置代理可以加快代码同步速度,对大项目很有必要。

  • # 设置
  • git config --global http.https://github.com.proxy socks5://127.0.0.1:1080
  • # 取消设置
  • git config --global --unset http.https://github.com.proxy

初始化仓库展开目录

新建文件夹 repositories/repo1 作为工作区 Working Directory/Workspace。进入工作区,通过 git initgit clone 命令创建一个本地仓库 / 版本库或下载远程版本库,该操作将会在工作区初始化一个 .git 文件夹,存储 版本库

  • # 递归创建目录
  • mkdir -p repositories/repo1
  • # 进入目录
  • cd repositories/repo1
  • # 初始化本地仓库
  • git init
  • # 不创建工作目录/工作区,用作远端共享版本库
  • # git init --bare
  • # 下载远端仓库
  • # git clone ssh://git@192.168.1.254/home/git/repo1
  • # 指定远程分支
  • # git clone -b dev ssh://git@192.168.1.254/home/git/repo1

提交变更展开目录

版本库中最重要的是暂存区 Stage/Index,每次在工作区 新建、修改或删除 文件后,都要使用 git add 将变更添加到暂存区,随后使用 git commit 将暂存区中的变更提交到当前 HEAD 指针指向的分支。首次 commit 时,GIT 会自动创建第一个分支 master 和指向 master 的指针 HEAD, 下面是工作区和版本库的示意图。

  • Workspace | Repository
  • dir1 | HEAD
  • |--file1 | ↘
  • |--file2 | Stage master
  • |--file3 add——→ | dir2 dir1
  • |--dir2 ↗ | |--file1 |--file1
  • |--file4 | |--file2 |--fiel2
  • |--file5 | ↘ |--file3
  • | commit——→ |--dir2
  • | |--file4
  • | |--file5
  • # 新建 HelloWorld.java 文件
  • cat > HelloWorld.java <<"EOF"
  • public class HelloWorld {
  • public static void main(String[] args) {
  • // Prints "Hello, World" to the terminal window.
  • System.out.println("Hello, World");
  • }
  • }
  • EOF
  • # 添加单个修改文件到暂存区
  • git add HelloWorld.java
  • # 添加所有修改文件
  • # git add .
  • # 提交变更到本地仓库
  • git commit -m "Initial commit."
  • # 查看提交记录
  • git log --oneline
  • # 撤销某次之后的所有提交
  • git reset <commit_hash>

commit message 包含 HeaderBodyFooter 三部分,一般仅使用 Header。按照 type(scope): subject 格式填写 Header 更有助于团队合作。scope 表示功能模块,subject 代表主题,type 为类型,一般定义如下:

  • feat:新功能
  • fix:修复 bug
  • style:更改格式
  • refactor:代码重构
  • chore:项目重建
  • git commit -m "fix(security): upgrade lodash.template"

辅助提交展开目录

nodejs 插件 commitizen,可以帮助你填入标准的 commit message,在此之前需要安装 nodejs,可以参考 该教程

  • # 安装 commitizen
  • npm install commitizen -g
  • # 使用 cz-conventional-changelog 包初始化 commitizen,
  • #+ 需要在项目仓库运行
  • npm init
  • commitizen init cz-conventional-changelog --save-exact
  • # 使用 git cz 代替 git commit 提交,之后根据提示填写 message
  • git cz

生成 Changelog 展开目录

使用 conventional-changelog 插件,可以方便地生成标准 Changelog,默认根据 commit messagefeatfix 生成。

  • # 安装 conventional-changelog
  • npm install conventional-changelog -g
  • # 生成 Changelog,-p(preset),
  • #+ -r 0 从首次 commit 开始生成,覆盖之前的 CHANGELOG.md
  • conventional-changelog -p angular -i CHANGELOG.md -s -r 0

文件状态追踪展开目录

仓库中的文件分为 已追踪未追踪 两种。已追踪文件在版本库中存在记录,用户工作一段时间后,这些文件仍可被查看。下面是文件状态变更图。

UnmodifiedModifiedStagedUntrackedEdit the fileStage the file(git add)Remove the fileAdd the fileCommitUnmodifiedModifiedStagedUntracked

通过 git status 可以查看到最近的文件状态变更,主要意义在于提醒开发者 commit 前应先 add,之后才可以 push

  • # 假设之前已经 commit 过
  • # 新增一个文件
  • touch newFile
  • # 修改一个文件
  • echo 1 >> oldFile1
  • # 删除一个文件
  • rm oldFile2
  • # 查看文件状态变更
  • git status
  • # newFile 属于 Untracked 文件
  • # oldFile1 属于 Modified 文件
  • # oldFile2 属于 Unstaged 中的 Deleted 文件

除了查看所有文件状态,通过 git diff 还可查看当前对某个文件的具体修改。

  • # 查看未暂存文件修改信息
  • git diff
  • # 查看已暂存文件修改信息
  • git diff --staged

忽略特定文件 / 文件夹展开目录

在某个目录新建 .gitignore 文件,并将需要忽略的文件 / 文件夹写入其中,即可在 git commit 时忽略它们,该文件的语法规则如下:

  • 每行一条规则
  • 空行用于增强可读性
  • # 开头的行将被当作注释,不参与解析
  • \ 开头的规则必须使用 \\
  • 行尾的若干空格将被忽略,除非使用 \ 注释每个空格
  • ! 前缀用于否定前面的规则,但对上级目录设定的规则无效,也不会对子目录中的文件生效,如文件以 ! 开头,要使用 \! 注释
  • 在名称后添加 / 解析为文件夹,如 foo/,表示忽略当前目录的 foo/ 及其子文件夹,不忽略 foo 文件
  • 不含 / 的规则会被当作 shell glob 匹配:* 匹配除了 / 的任何字符串,? 匹配除了 / 的单个字符,[] 匹配特定范围的单个字符
  • 行首的 / 用来避免递归,如 /*.c 匹配 cat-file.c,不匹配 mozilla-sha1/sha1.c
  • 与完整路径名匹配的连续两个 ** 可能有特殊意义:

    • ** 开头后跟 / 匹配所有路径下的文件。如 **/foo 匹配任何地方的 foo 文件或路径。**/foo/bar 匹配 foo 目录下任何地方的 bar 文件或路径
    • /** 结尾的规则匹配目录下的所有文件和路径,如 abc/** 匹配 abc 及其子目录下的所有文件
    • /**/ 匹配零个或多个目录。如 a/**/b 匹配 a/ba/x/ba/x/y/b 等等

操作远程仓库展开目录

远程仓库、origin、本地仓库、暂存区和工作目录的关系。

  • remote repository ——-
  • | |
  • git fetch | | git pull
  • ↓ |
  • origin(remote name) |
  • local repository ←--
  • git commit|
  • |
  • index
  • git add |
  • |
  • working directory
  • # 与多个远程仓库建立连接,origin 是远程仓库别名
  • git remote add origin ssh://git@192.168.1.254/home/git/repo0
  • git remote add origin1 ssh://git@192.168.1.254/home/git/repo1
  • # 删除与远程仓库的连接
  • git remote remove origin
  • # 查看所有 remote 地址
  • git remote -v
  • # 将本地分支推送至远程仓库的 master 分支
  • #+ -u | --set-upstream,设置默认提交上游,
  • #+ 执行一次后,之后提交直接 git push 即可
  • git push -u origin master
  • # git push -u origin1 master
  • # 删除远程分支
  • git push origin -d dev
  • # git push origin1 -d dev
  • # 推送 tag 到远程分支
  • git push --tag origin dev

处理冲突展开目录

假如你的协作者和你同时拉取最新版本代码并对同一文件进行修改,当你想把变更推送至远端,而他人先于你推送时便会发生冲突,此时需要使用 git mergegit rebase 手动合并你的变更,随后才能推送。GIT 会把文件中的冲突区域标记在 <<<<<<< HEAD>>>>>>> [other/branch/name] 之间,中间用 ======= 隔开。

使用 git merge 合并时,会一次性解决之前所有提交的冲突,而 git rebase 仅解决一次提交发送的冲突,这意味着开发者之后还要执行多次 git rebase --continue 操作。

  • # 保存本地代码
  • # git stash
  • # 使用 merge 合并
  • # git fetch
  • # git merge
  • git pull
  • # 使用 rebase 合并
  • # git rebase
  • # git rebase --continue
  • # 合并本地与远程
  • # git stash pop
  • # 冲突区域示意
  • cat conflictFile
  • <<<<<<< HEAD
  • int a=1;
  • =======
  • int a= 0;
  • >>>>>>> master

冲突处理完毕后需要将其重新添加到暂存区,再提交到本地仓库,随后提交到远程仓库。

  • git add .
  • git commit -m "refactor(Login): Merge file"
  • git push

管理分支展开目录

开始时,HEAD 指针指向 master 分支,master 指向最新提交,,两个指针随着 commit 不断后移如此,如此就能确定当前分支和当前提交点。

  • HEAD
  • master
  • ◯——————◯——————◯
  • v1 v2 v3

创建新分支并切换展开目录

一般 master 分支用于发布新版本,dev 分支用来开发,hotfix 分支用来修复 bug。创建新分支并切换时,HEAD 指针会执行它。

  • # 创建分支
  • # git branceh dev
  • # 切换分支
  • # git checkout dev
  • # 可合并为一条命令
  • git checkout -b dev
  • master
  • ◯——————◯——————◯
  • v1 v2 v3
  • \
  • dev
  • HEAD

此时,如果再进行一次提交,master 仍会停留在原位置,dev 后移指向最新提交。

  • # 一些修改
  • # ...
  • # 提交变更
  • git commit -m "refactor(Login): change code structure"
  • master
  • ◯——————◯——————◯
  • v1 v2 v3
  • \
  • \
  • dev1
  • dev
  • HEAD

合并分支展开目录

假设开发到 dev2 时已趋于稳定,计划合并到主分支,可通过 git mergegit rebase 进行分支合并,若使用前者,两个分支在合并后都会指向公共的提交;若使用后者,将被合并分支的提将被拷贝到当前分支上,被合并分支没有提交记录。

  • HEAD
  • master
  • ◯——————◯——————◯——————◯——————◯——————◯
  • v1 v2 v3 v4 v5 v6
  • \ /
  • \ /
  • ◯ /
  • dev1 /
  • | /
  • ◯———————————————
  • dev2
  • dev
  • [git merge]
  • --------------------------------------------
  • [git rebase]
  • HEAD
  • master
  • ◯——————◯——————◯——————◯——————◯——————◯——————◯
  • v1 v2 v3 v4 v5 dev1' dev2'
  • \
  • \
  • dev1
  • |
  • dev2
  • dev
  • # 切换回最终分支
  • git checkout master
  • # git fetch orign master
  • # git pull 等于 git fetch + git merge
  • # 将 dev 合并过来
  • git merge dev
  • # git rebase dev
  • # 撤销合并
  • git merge --abort
  • # git rebase --abort
  • # 回滚到合并前状态
  • # git reset --hard
  • # git reset <commit_hash> --hard

删除分支展开目录

  • # 删除
  • git branch -d dev
  • # 查看所有分支
  • git branch

标签管理展开目录

标签一般用作版本号,打上的标签是固定的,不像分支那样可以移动位置。

  • HEAD
  • master
  • ◯——————◯——————◯
  • | | |
  • v1 v2 v3
  • # 查看所有标签
  • git tag
  • # 查看某些标签,-l(list)
  • git tag -l v0.0.*
  • # 为当前提交加标签,-a(add) -m(message)
  • git tag -am "This is the first version." v1
  • # 为之前某次提交打标签
  • # 查看提交记录
  • git log --oneline
  • # 加上 commit hash 前几位(可区分即可)
  • git tag 4a48e8e5f60c -am "This is the first version." v0.9
  • # 删除标签,-d(delete)
  • git tag -d v1
  • # 推送标签
  • git push --tag

撤销和回滚展开目录

可以撤销 commit 之前和之后的变更,commit 之前的变更包括未进暂存区和已进入暂存区的更改。

  • # 修改文件
  • echo "new content" >> oldFile
  • git status
  • # 未进暂存区,使用 checkout 撤销
  • # 撤销单个文件
  • git checkout --oldFile
  • # 撤销所有文件
  • git checkout
  • git status
  • ##############################
  • echo "new content" >> oldFile
  • git add .
  • git status
  • # 已进入暂存区,使用 reset HEAD 将其拉出
  • # 拉出单个文件
  • git reset HEAD oldFile
  • # 拉出所有文件
  • git reset HEAD
  • git status
  • ##############################
  • echo "new content" >> oldFile
  • git add .
  • git commit -m "refactor[Login]: add some function"
  • git push
  • git log
  • # 撤销已有提交,revert 实际上是一次新的 commit
  • git revert <commit_hash>
  • # 再次 revert 又可恢复提交
  • git revert <revert_commit_hash>
  • git push

当需要回滚到某次提交时,可使用 get reset 命令,与 revert 不同,该操作不会生成提交记录,因此是不可逆操作,须谨慎使用。

  • git reset --hard <commit_hash>
  • git push --force

在 IDEA 中操作 GIT 展开目录

添加工程到本地仓库展开目录

  • 依次进入菜单 File -> Settings -> Version Control -> Git,配置 git.exe 路径
  • 新建项目,依次进入菜单 VCS -> Import into Version Control -> Create Git Repository,选择项目上层目录
  • 此时面板上会出现 Git 菜单,点击 Commit 图标,选择需要提交的文件和文件夹,填入 message 提交即可

远程仓库的克隆和推送展开目录

  • 依次进入菜单 File -> New -> Project from Version Contrl -> Git,添加远程仓库地址
  • 测试 ssh 方式 Windows 下不可用,使用 https 方式,输入用户名密码确定即可克隆
  • 推送时,点击 Git 菜单的 Commit,选择 Commit and Push

操作分支展开目录

  • 依次进入菜单 VCS -> Git -> Branches,选择 New BranchCheckout Tag or Revision

完整项目示例展开目录

  • ############## 项目创建 ##############
  • # 创建文件夹
  • mkdir repo
  • # 进入文件夹
  • cd repo
  • # 初始化仓库
  • git init
  • # 配置用户名
  • git config user.name "logi"
  • # 配置邮箱
  • git config user.email "logi@logi.im"
  • # 配置命令别名
  • git config --global alias.pull pl
  • git config --global alias.push ps
  • git config --global alias.commit cm
  • git config --global alias.merge mg
  • git config --list
  • # 添加 .gitignore 文件
  • cat > .gitignore <<'EOF'
  • # nodejs 相关
  • node_modules/
  • npm-debug.log*
  • yarn-debug.log*
  • npm-error.log*
  • # 编译后文件
  • /dist/
  • # 编辑器配置
  • .DS_Store
  • .idea
  • .vscode
  • *.suo
  • *.njsproj
  • *.sln
  • EOF
  • # 添加 README 文件
  • cat > README.md << 'EOF'
  • # Git 命令详解
  • EOF
  • # 进行首次提交
  • git add .
  • git commit -m "chore(all): initial project"
  • # 与远程仓库建立连接
  • git remote add origin ssh://git@192.168.1.254/home/git/repo
  • # 查看所有远程仓库
  • git remove -v
  • # 推送到远程仓库
  • git push -u origin master
  • ############## 本地开发 ##############
  • # 建立新分支
  • git branch logi
  • # 切换到新分支
  • git checkout logi
  • # 在 logi 分支模拟开发
  • cat > index.js << 'EOF'
  • const http = require('http');
  • const hostname = '127.0.0.1';
  • const port = 3000;
  • const server = http.createServer((req, res) => {
  • res.statusCode = 200;
  • res.setHeader('Content-Type', 'text/plain');
  • res.end('Hello World\n');
  • });
  • server.listen(port, hostname, () => {
  • console.log(`Server running at http://${hostname}:${port}/`);
  • });
  • EOF
  • # 查看最近变更
  • git status
  • # 将变更加入暂存区
  • git add .
  • # 提交变更
  • git commit -m "feat(index): add project index"
  • # 推送到远程仓库
  • git push -u origin logi
  • ############## 项目上线 ##############
  • # 切换到 master 分支
  • git checkout master
  • # 合并 logi 分支
  • git merge logi
  • # 推送到远端 master 分支
  • git push -u origin master
  • # 打 tag
  • git tag -a v0.1.0 -m "First version"
  • # 推送 tag 到远程分支
  • git push --tag origin master
  • ############## 问题修复 ##############
  • # 建立新分支并切换
  • git checkout -b hotfix-718
  • # 模拟修复过程
  • echo >> index.js <<'EOF'
  • function hotfix718() { //... }
  • hotfix718;
  • EOF
  • # 提交代码
  • git add .
  • git commit -m "fix(index): fix ui bugs"
  • git push -u origin hotfix-415
  • # 切换回 master 分支
  • git checkout master
  • git merge hotifix-718
  • git push
  • # 打上新版本并提交
  • git tag -a v0.1.1 -m "Fix bugs"
  • git push --tag origin master
  • # 删除 hotfix 分支
  • git branch -d hotfix-718
  • git push origin -d hotfix-718
  • ############## 继续开发 ##############
  • # 切换到个人分支 logi
  • git checkout logi
  • # 修改某个模块
  • echo > index.js <<'EOF'
  • // ...
  • EOF
  • # 发现忘记拉取 master 最新代码,
  • #+ 此时需要保存工作
  • git stash
  • # 拉取最新代码
  • git pull origin master
  • # 恢复暂存文件,之后可能需要处理冲突
  • git stash pop
  • # 提交修改
  • git add .
  • git commit -m "feat(index): add auth module"
  • git push
  • # 合并到 master 并推送
  • git checkout master
  • git merge logi
  • git push origin master
  • # 打上新版本并提交
  • git tag -a v0.1.2 -m "Fix bugs"
  • git push

参考文献展开目录

TG 大佬群 QQ 大佬群

最后编辑于: 2020 年 05 月 31 日
返回文章列表 文章二维码
本页链接的二维码
打赏二维码
添加新评论

Loading captcha...

  • OωO
  • |´・ω・)ノ
  • ヾ(≧∇≦*)ゝ
  • (☆ω☆)
  • (╯‵□′)╯︵┴─┴
  •  ̄﹃ ̄
  • (/ω\)
  • ∠( ᐛ 」∠)_
  • (๑•̀ㅁ•́ฅ)
  • →_→
  • ୧(๑•̀⌄•́๑)૭
  • ٩(ˊᗜˋ*)و
  • (ノ°ο°)ノ
  • (´இ皿இ`)
  • ⌇●﹏●⌇
  • (ฅ´ω`ฅ)
  • (╯°A°)╯︵○○○
  • φ( ̄∇ ̄o)
  • ヾ(´・ ・`。)ノ"
  • ( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
  • (ó﹏ò。)
  • Σ(っ °Д °;)っ
  • ( ,,´・ω・)ノ"(´っω・`。)
  • ╮(╯▽╰)╭
  • o(*////▽////*)q
  • >﹏<
  • ( ๑´•ω•) "(ㆆᴗㆆ)
  • (。•ˇ‸ˇ•。)
  • 泡泡
  • 阿鲁
  • 蛆音娘
  • 小埋
  • 颜文字

已有 4 条评论
  1. 强调几点:(该留言由系统自动生成!)
    1. 请不要刷广告,本站没有流量!
    2. 我不回复虚假邮箱,因为回复了你也看不到!
    3. 存在必须回复的隐藏内容时,可以直接使用表情框里的阿鲁表情!

  1. q q   Windows 10 x64 Edition  Google Chrome 63.0.3239.132

    图怎么画的?

    1. LOGI LOGI   Windows 10 x64 Edition  Google Chrome 80.0.3987.132

      @qtxt 画,信吗

  2. 王奥OX 王奥OX   Mac OS X 10.14.6  Google Chrome 79.0.3945.88

    博主的文章很细致,我可以申请个人转载 Git 和 SVN 这两篇文章吗

    1. LOGI LOGI   Windows 10 x64 Edition  Google Chrome 79.0.3945.88

      @王奥 OX 可以的,承蒙厚爱,文章里有一些错别字,并且只是入门用法,你可以改进一下