Git
1.历史
同生活中的许多伟大事物一样,
Git
诞生于一个极富纷争大举创新的年代.Linux 内核开源项目有着为数众多的参与者. 绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间), 到 2002 年,整个项目组开始启用一个专有的分布式版本控制系统
BitKeeper
来管理和维护代码.到了 2005 年,开发
BitKeeper
的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了 Linux 内核社区免费使用BitKeeper
的权力.这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds)基于使用BitKeeper
时的经验教训,开发出自己的版本系统.他们对新的系统制订了若干目标:
- 速度
- 简单的设计
- 对非线性开发模式的强力支持(允许成千上万个并行开发的分支)
- 完全分布式
- 有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量)
自诞生于 2005 年以来,
Git
日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标.它的速度飞快,极其适合管理大项目,有着令人难以置信的非线性分支管理系统.
2.基本概念
1.Git
是什么
对比其他的版本工具,会发现
Git
根本上的不同.
VCS\Subversion\Perforce
等,会将它们存储的信息看作是一组基本文件和每个文件随时间逐步累积的差异(delte-based
)
Git
最大的不同是,他会把数据看作是小型文件系统的一系列快照,每当提交更新或保存项目状态时,它基本上就会对当时的全部文件创建一个快照并保存这个快照的索引.为了效率.如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件.综合以上,
Git
更像是一个小型的文件系统.
2.Git
中文件状态
Git
中,文件可能会处于以下其中一种状态.
Committed
(已提交):数据已经安全地保存在本地数据库中Modified
(已修改):修改了文件,但还没保存到数据库中Staged
(已暂存):对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中
3.Git
文件逻辑流程
一个文件,只能经过以下的流程状态
4.Git
文件逻辑状态
Untrucked
:未跟踪, 此文件在文件夹中, 但并没有加入到git库, 不参与版本控制. 通过git add
状态变为Staged
.
Unmodify
: 文件已经入库, 未修改, 即版本库中的文件快照内容与文件夹中完全一致. 这种类型的文件有两种去处, 如果它被修改, 而变为Modified
. 如果使用git rm
移出版本库, 则成为Untracked
文件.
Modified
: 文件已修改, 仅仅是修改, 并没有进行其他的操作. 这个文件也有两个去处, 通过git add
可进入暂存staged
状态, 使用git checkout
则丢弃修改过, 返回到unmodify
状态, 这个git checkout
即从库中取出文件, 覆盖当前修改.**
Staged
**:暂存状态,执行git commit
则将修改同步到库中,这时库中的文件和本地文件又变为一致, 文件为Unmodify
状态. 执行git reset HEAD filename
取消暂存, 文件状态为Modified
3.安装Git
ubuntu
$ sudo apt install git
windows
https://git-scm.com/
下载对应的版本安装
4.Git
命令
注意:此图片使用
xmind
生成.如果图片不清晰,请下载原始文件:https://gitee.com/ningwenyan/font
如果需要
xmind
破解版软件,可直接在公众号回复xmind
.
1.获取帮助git help
$ git help 用法:git [--version] [--help] [-C <path>] [-c <键名>=<值>] [--exec-path[=<路径>]] [--html-path] [--man-path] [--info-path] [-p | --paginate | --no-pager] [--no-replace-objects] [--bare] [--git-dir=<路径>] [--work-tree=<路径>] [--namespace=<名称>] <命令> [<参数>] 这些是各种场合常见的 Git 命令: 开始一个工作区(参见:git help tutorial) clone 克隆一个仓库到一个新目录 init 创建一个空的 Git 仓库或重新初始化一个已存在的仓库 在当前变更上工作(参见:git help everyday) add 添加文件内容至索引 mv 移动或重命名一个文件、目录或符号链接 reset 重置当前 HEAD 到指定状态 rm 从工作区和索引中删除文件 检查历史和状态(参见:git help revisions) bisect 通过二分查找定位引入 bug 的提交 grep 输出和模式匹配的行 log 显示提交日志 show 显示各种类型的对象 status 显示工作区状态 扩展、标记和调校您的历史记录 branch 列出、创建或删除分支 checkout 切换分支或恢复工作区文件 commit 记录变更到仓库 diff 显示提交之间、提交和工作区之间等的差异 merge 合并两个或更多开发历史 rebase 在另一个分支上重新应用提交 tag 创建、列出、删除或校验一个 GPG 签名的标签对象 协同(参见:git help workflows) fetch 从另外一个仓库下载对象和引用 pull 获取并整合另外的仓库或一个本地分支 push 更新远程引用和相关的对象 命令 'git help -a' 和 'git help -g' 显示可用的子命令和一些概念帮助。 查看 'git help <命令>' 或 'git help <概念>' 以获取给定子命令或概念的 帮助。
2.配置命令git config
在初始化仓库之前,最需要做的是配置用户名和电子邮件,这两条配置非常重要,每次
Git
提交时都会引用这两条信息,用于说明是谁提交了更新.$ git config -help usage: git config [<options>] Config file location --global use global config file #全局变量 --system use system config file # 登陆系统的账户 --local use repository config file # 局部本地设置,针对当前的项目中的独立设置,优先级高于global --worktree use per-worktree config file -f, --file <file> use given config file --blob <blob-id> read config from given blob object
其中有3个选项可供选择.
--global
:全局变量,--system
:只针对当前登录到系统的用户--local
:局部本地设置,针对当前的项目中的独立设置,优先级高于global
git config --global user.name "用户名" # 设置用户名 git config --global user.email "用户邮箱" #设置邮箱 git config --global user.name # 查看用户名是否配置成功 git config --global user.email # 查看邮箱是否配置 # 其他查看配置相关 git config --global --list # 查看全局设置相关参数列表 git config --local --list # 查看本地设置相关参数列表 git config --system --list # 查看系统配置参数列表 git config --list # 查看所有Git的配置(全局+本地+系统)
3.初始化仓库git init
进入要初始化的文件目录,然后创建
Git
仓库$ git init
例如:
❯ cd temp ❯ mkdir git_learn ❯ cd git_learn ❯ git init 已初始化空的 Git 仓库于 /home/kning/temp/git_learn/.git/
4.添加文件到暂存区git add
$ git add -help usage: git add [<options>] [--] <pathspec>... -n, --dry-run dry run -v, --verbose be verbose -i, --interactive interactive picking -p, --patch[=<patch-mode>] select hunks interactively -e, --edit edit current diff and apply -f, --force allow adding otherwise ignored files -u, --update update tracked files --renormalize renormalize EOL of tracked files (implies -u) -N, --intent-to-add record only the fact that the path will be added later -A, --all add changes from all tracked and untracked files --ignore-removal ignore paths removed in the working tree (same as --no-all) --refresh don't add, only refresh the index --ignore-errors just skip files which cannot be added because of errors --ignore-missing check if - even missing - files are ignored in dry run --chmod (+|-)x override the executable bit of the listed files
常用的有
git add 文件名 # 添加单个文件 git add -u # update被tracked 文件 git add -A # 添加所有 git add . # 添加当前工作区中所有文件
5.提交本地仓库git commit
提交修改
git commit -m "description" # 提交本地仓库,并添加描述
6.查看working tree
状态
# git status 官方解释是 show the working tree ,应该是能查看一个文件所有的逻辑状态信息 git status git status -s # 结果以简短的形式输出
7.查看差异变化git diff
# git-diff - Show changes between commits, commit and working tree, etc # 显示提交,提交和working tree 之间的所有的更改 git diff # 工作区与缓存区的差异 git diff 分支名 #工作区与某分支的差异,远程分支这样写:remotes/origin/分支名 git diff HEAD # 工作区与HEAD指针指向的内容差异 git diff 提交id 文件路径 # 工作区某文件当前版本与历史版本的差异 git diff --stage # 工作区文件与上次提交的差异(1.6 版本前用 --cached) git diff 版本TAG # 查看从某个版本后都改动内容 git diff 分支A 分支B # 比较从分支A和分支B的差异(也支持比较两个TAG) git diff 分支A...分支B # 比较两分支在分开后各自的改动 # 另外:如果只想统计哪些文件被改动,多少行被改动,可以添加 --stat 参数
8.查看历史记录git log
git log # 查看所有commit记录(SHA-A校验和,作者名称,邮箱,提交时间,提交说明) git log -p -次数 # 查看最近多少次的提交记录 git log --stat # 简略显示每次提交的内容更改 git log --name-only # 仅显示已修改的文件清单 git log --name-status # 显示新增,修改,删除的文件清单 git log --oneline # 让提交记录以精简的一行输出 git log –graph –all --online # 图形展示分支的合并历史 git log --author=作者 # 查询作者的提交记录(和grep同时使用要加一个--all--match参数) git log --grep=过滤信息 # 列出提交信息中包含过滤信息的提交记录 git log -S查询内容 # 和--grep类似,S和查询内容间没有空格 git log fileName # 查看某文件的修改记录
9..gitignore
未
tracked
的文件添加到缓存区后,Git
就会开始跟踪这个文件.对于一些比如:自动生成的文件,日志,临时编译文件等,就 没必要进行跟踪了,这个时候可以编写.gitignore
文件,在里面 把不需要跟踪的文件或文件夹都写上,git
就不会对这些文件进行跟踪.
另外.gitignore
文件与.git
文件夹在同级目录下.已我上面刚创建的目录为例:
- 创建
.gitigore
$ cd git_learn $ touch .gitignore $ vim .gitignore ... # 忽视c结尾文件 *.c
- 提交版本控制,注意
.gitignore
是可以版本控制的.$ git add . $ git commit -m 'add ignore file'
- 尝试添加一个
.c
文件.检验的方法就是创建完毕后,执行git status
,工作区是clean
的,干净的.$ touch text.c $ git status 位于分支 master 无文件要提交,干净的工作区
如果不想自己写,可以直接到:https://github.com/github/gitignore 复制粘贴.
示例:
# 忽略所有以 .c结尾的文件 *.c # 但是 stream.c 会被git追踪 !stream.c # 只忽略当前文件夹下的TODO文件, 不包括其他文件夹下的TODO例如: subdir/TODO /TODO # 忽略所有在build文件夹下的文件 build/ # 忽略 doc/notes.txt, 但不包括多层下.txt例如: doc/server/arch.txt doc/*.txt # 忽略所有在doc目录下的.pdf文件 doc/**/*.pdf
注意:配置
.gitignore
只对那些没有添加到版本控制系统的文件生效(未Tracked的文件)比如:有
A,B
两个文件,你先把他两个add
,然后在.gitignore
文件中 配置了不跟踪这两个文件,那么命令不会生效.所以,最好的做法就是在项目刚开始的时候,先添加
.gitignore
文件.当然,即使是发生了,还是有解决方法的,可以键入下述命令清除标记状态,然后先添加.gitignore
,再添加文件即可:git rm -r --cached . # 清除版本控制标记,.代表所有文件,也可指定具体文件
5.版本回溯
1.文件恢复git checkout
切换分支或恢复文件
$ git checkout -- filename # 丢球工作区中的某个文件修改 $ git checkout -- . # 丢弃工作区中的所有修改 $ touch 2.txt >$ git status On branch master Untracked files: (use "git add <file>..." to include in what will be committed) 2.txt nothing added to commit but untracked files present (use "git add" to track) $ git add 2.txt $ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: 2.txt $ git commit -m 'add 2.txt' [master 353e702] add 2.txt 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 2.txt $ git status On branch master nothing to commit, working tree clean $ rm 2.txt $ git status On branch master Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) deleted: 2.txt no changes added to commit (use "git add" and/or "git commit -a") $ git checkout 2.txt Updated 1 path from the index $ git status On branch master nothing to commit, working tree clean $ ls 2.txt
2.git reset
每次的更改都会在
git
中留下记录值HEAD
也就是commit id
.根据这个HEAD
可以跳回到原来的状态.$ git reset
可以通过
git log
来查看更改的HEAD
值# 新建一个测试文件 $ touch 3.txt # 编辑测试文件,并添加数字 1,2,3,4 $ vim 3.txt $ git status On branch master Untracked files: (use "git add <file>..." to include in what will be committed) 3.txt $ git add 3.txt $ git commit -m "add 3.txt" [master e38dbcb] add 3.txt 1 file changed, 4 insertions(+) create mode 100644 3.txt $ git status On branch master nothing to commit, working tree clean # 在测试文件中新添加数字 5 $ vim 3.txt $ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: 3.txt no changes added to commit (use "git add" and/or "git commit -a") $ git add 3.txt $ git commit -m 'add 5 in 3.txt' [master 840106f] add 5 in 3.txt 1 file changed, 1 insertion(+) $ git status On branch master nothing to commit, working tree clean # 查看commit id $ git log commit 840106f762192b023f26abfd1e6c2a55b96379f5 (HEAD -> master) add 5 in 3.txt $ ls 2.txt 3.txt test.txt test1 $ cat 3.txt 1 2 3 4 5 # 回溯文件的 commit id $ git reset --hard e38dbcb124 # id号不用写全 HEAD is now at e38dbcb add 3.txt $ ls 2.txt 3.txt test.txt test1 c $ cat 3.txt 1 2 3 4
3.查看历史命令git reflog
$ git reflog # 查看指令,但是不会永久保存,git会自己定时清理
4.查看某次提交的内容git show
$ git show "commit id"
5.查看分支版本号
$ git rev-parse 分支名
6.分支
1.分支的创建/切换
# 创建分支 $ git branch 分支名 # 查看分支 $ git branch # 切换分支 $ git checkout 分支名 # 创建分支并切换到这个分支 $ git checkout -b 分支名
示例:
# 创建分支1 $ git branch branch_1 # 查看所有的分支 $ git branch branch_1 * master # 创建分支2 $ git branch branch_2 # 切换分支2 $ git checkout branch_2 Switched to branch 'branch_2' # 创建文件 $ touch 2.txt $ vim 2.txt # 分支2中查看到2个文件 $ ls 1.txt 2.txt $ git add . $ git commit -m "add 2.txt in branch_2" # 切换到主分支 $ git checkout master Switched to branch 'master' # 查看到只有1个文件 $ ls 1.txt # 查看所有的分区和所处的分区(* 为所在分区) $ git branch branch_1 branch_2 * master
GUI
界面中查看更容易:
2.分支合并
当我们修复完
bug
或者是开发新的特性后,需要合并回原理的主分支上.$ git merge # Join two or more development histories together $ git rebase # Reapply commits on top of another base tip
3.分支删除
当分支完成自己的使命后,分支就不需要了,可以删除他
$ git branch -d 分支名
7.远程仓库
1.创建SSH KEY
为了演示方便使用
gitee
如果本地用户主目录中没有
.ssh
目录,则需要手动创建ssh_key
$ ssh-keygen -t rsa -C "youremail@example.com" # 使用默认值即可 $ cd .ssh/ $ ls id_rsa # 私钥,不能泄露 id_rsa.pub # 公钥,需要上传给服务器
2.上传公钥
登录
gitee
,并上传ssh公钥
3.新建一个远程仓库
如图:
4.推送本地库到远程库
# 关联本地仓库和远程仓库 git remote add origin 远程仓库地址 # 使用git 地址 >$ git remote add origin git@gitee.com:ningwenyan/test.git $ git remote -v origin git@gitee.com:ningwenyan/test.git (fetch) origin git@gitee.com:ningwenyan/test.git (push)
之后,可以正常的
git push
和git pull
进行推送$ git push -u origin master ># -u参数 作为第一次提交使用, # 作用是把本地master分支和远程master分支关联起来(设置默认远程主机), # 后续提交不需要这个参数!
其他命令
git remote set-url origin 远程仓库地址 ># 也可以先删除origin后再添加 git remote rm origin # 删除仓库关联 git remote add origin 远程仓库地址 # 添加仓库关联
windows系统添加用户名密码错误修改方法:可以在控制面板中找到
凭据管理器
删除错误的用户名密码,然后重新登录.本电脑不知是不是因为输错密码的缘故,弹出错误提示如下
To gitee.com:ningwenyan/test1.git >! [rejected] master -> master (non-fast-forward) error: failed to push some refs to 'git@gitee.com:ningwenyan/test1.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
解决办法:使用git pull 合并分支
git pull -u -f origin master # 第一次加-f 后续就不用添加了
5.从远程仓库克隆
远端新建仓库
执行如下命令
$ git clone git@gitee.com:ningwenyan/test2.git Cloning into 'test2'... remote: Enumerating objects: 4, done. remote: Counting objects: 100% (4/4), done. remote: Compressing objects: 100% (4/4), done. remote: Total 4 (delta 0), reused 0 (delta 0) Receiving objects: 100% (4/4), done. $ ls test2/ $ cd test2/ $ ls README.en.md README.md
8.标签
打标签的作用,就是给项目的开发节点,加上语义化的名字,也即功能版本的别名. 打上标签名的同时,写上附带信息,可以方便项目日后维护过程中的回溯和复查.
另外,也可以通过标签记录,大致了解当前项目的向下兼容性,API的修改和迭代情况.
1.创建标签
$ git tag -a "tagname" -m "comment" "commit_id" # -a 标签名 # -m 备注信息 # commit_id 提交id
示例:
$ git tag -a 'v0.1.0' -m "初始"
类似
v0.1.0
遵从一个简单的规范
- 主版本号: 当你做了不兼容的
API
修改- 次版本号: 向下兼容的功能性增加
- 修订号: 向下兼容的问题修正
2.查看所有标签
$ git tag
3.查看具体标签信息
$ git show tagname
4.删除本地标签
$ git tag -d tagname