一, 安装
具体查看 安装 Git
二, 使用
基础知识
工作区(Workspace): 就是你在电脑里能看到的项目目录.
暂存区 (Index / Stage): 临时存放更改的地方, 使用命令 "git add <.|file>" 就是把文件加入暂存区. 一般存放在 ".git 目录下" 下的 index 文件(.Git/index) 中, 所以我们把暂存区有时也叫作索引(index).
版本库(Repository): 管理版本的文件, 使用 "git commit -m'description'" 就是把暂存区的文件提交到版本库. 工作区有一个隐藏目录. Git, 这个不算工作区, 而是 Git 的版本库.
远程仓库(Remote): 托管代码的服务器. 可以简单的认为是你项目组中的一台电脑用于远程数据交换
一张图描述 Git 的文件如何在各个区域之前流转:
origin: 远程仓库库默认别名
master: 仓库默认分支的名称
本地项目初始化 / 和远程仓库操作
Git init, 把当前文件夹初始化位 Git 工程
Git remote add [<options>] <name> <url> 把当前文件夹关联远程仓库并命名, 比如 Git remote add origin Git@server-name:path/repo-name.Git;
Git remote -v 查看远程仓库地址
Git push <远程主机名> <本地分支名> <远程分支名>, 比如 Git push origin dev dev
Git push -u origin master 如果当前分支与多个主机存在追踪关系, 则可以使用 -u 参数指定一个默认主机, 这样后面就可以不加任何参数使用 Git push
基本操作: 添加 / 提交 / 查看记录
"git add ." 或者 "git add <file>", 将所有文件或指定文件从工作区添加到暂存区
Git commit -m "description", 将暂存区的所有文件提交到版本库
Git show <commitId> <filename> : 查看提交详情
Git status, 查看当前工作区和暂存区的文件状态
Git diff, 查看当前工作区对比暂存区的更改
Git diff HEAD -- readme.txt 命令可以查看工作区和版本库里面最新版本的区别
"git log" 或 "git log <file>", 查看版本库或者指定文件的提交记录
Git log --graph 命令可以看到分支合并图.
Git log --pretty=oneline --graph --abbrev-commit 展示效果如下
Git cherry-pick <commitId>, 复制一个特定的提交到当前分支, 比如 master 分支的 bug 修复提交复制到 dev 分支
若要合并某个分支上的一系列提交, 这种情况就 cherry-pick 就不适用了.
需要使用 rebase 指令进行合并操作
具体操作步骤:
// 以 ** 最后一次提交 ** 为节点, 创建一个新的分支 < newbranch 是新分支的名字>
1. Git checkout -b newbranch 最后一次提交的 id
// 再 rebase 这个新分支的 commit 到目标分支上<--onto 目标分支>.<start_id> 指明你想从哪个特定的 commit 开始.
2. Git rebase --onto 目标分支 start_id
仓库分支管理
查看分支: Git branch
创建分支: Git branch <name>
切换分支: Git checkout <name > 或者 Git switch <name>
创建 + 切换分支: Git checkout -b <name > 或者 Git switch -c <name>
比如 Git checkout -b dev, 切换并创建 dev 分支, 相当于
- $ Git branch dev
- $ Git checkout dev
合并某分支到当前分支: Git merge <name>
正常合并如果能用 fast-forward 就会使用, 但这种模式下, 删除分支后, 会丢掉分支信息. 可以使用 --no-ff 强制禁用 ff 模式
Git merge --no-ff -m "merge with no-ff" dev
因为本次合并要创建一个新的 commit, 所以加上 - m 参数, 把 commit 描述写进去.
删除分支: Git branch -d <name>
代码回退
看上面的几个区域的图基本就能明白
"git reset HEAD" 或者 "git reset HEAD <file>" 命令, 暂存区的目录树或文件会被重写, 被 master 分支指向的目录树或文件所替换, 但是工作区不受影响.
Git reset --hard HEAD^/Git reset --hard 1094a, 强制回退上一个版本 / 回退到指定版本号的版本, 版本库会直接回退(远程仓库不会回退), 需要特别谨慎. 版本号没必要写全, 前几位就可以了, Git 会自动去找. 当然也不能只写前一两位, 因为 Git 可能会找到多个版本号, 就无法确定是哪一个了
"git rm --cached <file>" 命令, 会直接从暂存区删除文件, 工作区则不做出改变.
"git checkout ." 或者 "git checkout -- <file>" 命令, 会用暂存区全部或指定的文件替换工作区的文件. 这个操作很危险, 会清除工作区中未添加到暂存区的改动.
"git checkout HEAD ." 或者 "git checkout HEAD <file>" 命令时, 会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件. 这个命令也是极具危险性的, 因为不但会清除工作区中未提交的改动, 也会清除暂存区中未提交的改动.
"git revert HEAD/git revert commitID": 放弃已经 push 的指定版本的修改, 会新增一条记录, 版本会递增
"git reflog" , 用来查看你的每一条命令, 用来配合上面的命令恢复你的误操作
例 1: 将单个文件 (a.JS) 回退到某一版本
Git log a.JS 查看 a.JS 的更改记录
Git reset fcd2093 a.JS 先将暂存区中的该文件回退到历史版本 fcd2093
Git checkout -- a.JS 暂存区中该文件的历史版本 (fcd2093) 覆盖工作区中对应的文件, 此时(工作区, 暂存区的文件 a.JS 是 fcd2093 版本).
[注] Git reset [选项] [版本号] [回退对象]命令, 当回退对象是文件时选项不能为 hard
[注] 2,3 步可以合并成一步 Git checkout fcd2093 a.JS
此时, 如果 Git commit 提交暂存区的数据到版本库, 则会重新生成一条记录
例 2: 将整个项目 (远程仓库和本地仓库当前版本一致) 回退到某个版本, 并 push 到远程仓库, 让远程仓库也回退.
例如, 版本库最新的几条提交记录是: aaaa -> bbbb -> cccc;cccc 是最新的提交记录, 要回退到 aaaa 并 push
Git reset --hard aaaa 强制将版本库回退到 aaaa, 但是远程仓库还是 cccc
Git reset cccc 将 head 移到最新的版本(和远程的 head 保持一致, 实际就是将远程暂存区的内容更新到最新版本 cccc, 工作区的内容还是保持在 aaaa), 此时 aaaa 和 cccc 的差异便作为本次更改的内容.
Git add / Git commit / Git push 提交后生成新的版本号 dddd
此时 Git log 看到的最近的提交记录就是: aaaa -> bbbb -> cccc -> dddd
[注] 也可以使用 Git revert cccc 和 Git revert bbbb 来实现, 不过会新增两条回滚记录
保留半成品现场(存储临时现场)
主要用在目前还不想提交的但是已经修改的内容进行保存至堆栈中, 后续可以在某个分支上恢复出堆栈中的内容
Git stash 存储临时现场
Git stash list 查看工作临时现场
一是用 Git stash apply 恢复, 但是恢复后, stash 内容并不删除, 你需要用 Git stash drop 来删除;
另一种方式是用 Git stash pop, 恢复的同时把 stash 内容也删了
你可以多次 stash, 恢复的时候, 先用 Git stash list 查看, 然后恢复指定的 stash, 用命令:
Git stash apply stash@{0}
子模块
有时工程太过庞大想要分出子工程单独管理, 或者纳入一个子工程到当前工程来, 就可能用到子模块功能.
Git 子模块配置处理(即 Git 的 B 仓库被作为 A 仓库的子目录), 两个仓库可以各自管理和提交
Git submodule add <path> <name>: 将 < path > 对应的仓库作为当前仓库 A 的 < name > 子目录
Git status: 在 A 中查看发现多了 < name > 和 .gitmodules(这个文件中是子模块的相关配置)
Git diff --cached <name>: 在 A 中看到无法查询子模块的提交记录, 取而代之的是, Git 将它记录成来自 B 仓库的一个特殊的提交(这个提交在克隆的该项目时, 进入子模块就是进入到这个提交)
例如, 子模块 B 的名称为 subproject_demo:
- $ Git diff --cached subproject_demo
- diff --Git a/subproject_demo b/subproject_demo
- new file mode 160000
- index 0000000..aa1eeb0
- --- /dev/null
- +++ b/subproject_demo
- @@ -0,0 +1 @@
- +Subproject commit aa1eeb06e67608d7a2af179a7dfd9e594777e90f
Git commit -m 'first commit with submodule xxx': 结果中注意 subproject_demo 条目的 160000 模式. 这在 Git 中是一个特殊模式, 基本意思是你将一个提交记录为一个目录项而不是子目录或者文件.
当你使用 clone 克隆该项目 (父工程 A) 时, 会发现子模块的文件夹内容为空, 需要做:
Git submodule init: 初始化你的本地配置文件
Git submodule update: 从子模块 B 拉取所有数据并检出你上层项目里所列的合适的提交(保持子模块是最新的那个)
进入子模块, 发现子模块是那个项目的 你先前提交的确切状态的分支
- chen_@DESKTOP-TJKEMKG MINGW64 /c/works/demo/subproject_demo ((aa1eeb0...))
- // 发现没: aa1eeb0 就是之前的哪个提交
如果你在项目中改了子模块的代码, 准备提交到对应的分支(add 和 commit 已经执行过), 使用:
Git push origin HEAD:<branch> 这样就把代码提交到对应的分支 , 和 Git push origin <localBranch> <remoteBranch > 类似
如果其他人有修改这个子模块并提交到 A 工程, 你可以重新 pull A 项目分支, 然后执行 Git submodule update 保证子模块也是最新的
Git clone --recurse-submodules <repositary> , 他就会自动初始化并更新仓库的每一个子模块
[注] 使用时要注意, 最好保证在父工程 A 中来自 B 的提交永远来自同一个 B 的分支, 比如 master 分支. 所以 B 的分支代码更改完毕并测试完毕合并到 master 后, 再在 A 提交来自 B 的 master 分支的提交
[注] 引入私有 Git 工程还可以又其他方式, 比如和 NPM 配合:《2018 年了, 你还是只会 NPM install 吗》查看 "私有 git 共享 package" 部分
https 和 SSH 使用
查看链接:
https 模式下添加 Git 账号到项目, push 不用每次输入账号密码
打开. Git 文件的下的 VIM .Git/config 新增以下内容
- [user]
- name = XXXX05@qq.com
- email = XXXX05@qq.com
- [credential]
- helper=store
三, 踩坑
[remote rejected] (hook declined)
完整日志:
- $ Git push
- Enumerating objects: 25, done.
- Counting objects: 100% (24/24), done.
- Delta compression using up to 8 threads
- Compressing objects: 100% (13/13), done.
- Writing objects: 100% (13/13), 1.20 KiB | 1.20 MiB/s, done.
- Total 13 (delta 11), reused 0 (delta 0)
- remote: Git: 'refs/heads/web2.0' is not a Git command. See 'git --help'.
- remote: error: hook declined to update refs/heads/web2.0
- To https://e.coding.net/tops/front-www.git
- ! [remote rejected] web2.0 -> web2.0 (hook declined)
- error: failed to push some refs to 'https://e.coding.net/tops/front-www.git'
百度查看帮助, 找到类似的问题:
本人的问题解决办法
Git config --global --unset branch.web2.0.merge
然后再 push 就 OK
来源: https://www.cnblogs.com/chuaWeb/p/git_all.html