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 init
或 git 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
包含 Header
,Body
和 Footer
三部分,一般仅使用 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 message
的 feat
和 fix
生成。
- # 安装 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
文件状态追踪展开目录
仓库中的文件分为 已追踪
和 未追踪
两种。已追踪文件在版本库中存在记录,用户工作一段时间后,这些文件仍可被查看。下面是文件状态变更图。
sequenceDiagram
Unmodified->>Modified: Edit the file
Modified->>Staged: Stage the file(git add)
Unmodified->>Untracked: Remove the file
Untracked->>Staged: Add the file
Staged->>Unmodified: Commit
通过 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/b
,a/x/b
,a/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 merge
或 git 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 merge
和 git 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 Branch
或Checkout 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
参考文献展开目录
如有问题请在下方留言,文章转载请注明出处,详细交流请加下方群组!请大佬不要屏蔽文中广告,因为它将帮我分担服务器开支,如果能帮忙点击我将万分感谢。
强调几点:(该留言由系统自动生成!)
1. 请不要刷广告,本站没有流量!
2. 我不回复虚假邮箱,因为回复了你也看不到!
3. 存在必须回复的隐藏内容时,可以直接使用表情框里的阿鲁表情!