发展
本地版本控制系统
用复制整个项目目录的方式来保存不同版本, 例如写论文;
坏处: 有时会混淆工作目录, 可能写错或覆盖意想外的文件.
集中式版本控制系统
有一个单一的集中管理的服务器, 保存所有文件的修订版本. 协同工作的人 (客户端) 取出最新的文件或提交更新.
好处: 相对于本地版本控制, 每个人可以一定程度上看到其他人在做什么, 管理员也能轻松掌握开发者的权限.
坏处: 中央服务器的单点故障. 如果宕机一小时, 这一小时内都无法提交更新, 也无法协同工作; 如果磁盘损坏, 又没有备份, 那将丢失所有数据, 只剩各机器上的单独快照.
分布式版本控制系统
如 Git. 客户端不止提取最新文件快照, 而是把代码仓库完整地镜像下来. 也是一次完整备份. 还可以指定和若干不同的代码仓库进行交互.
Git 基础
直接记录快照, 而非差异比较
其他系统: 以文件变更列表的方式存储信息, 存储每个文件与初始版本的差异.
Git: 把数据看作是对小型文件系统的一组快照, 并保存快照的索引.
近乎所有操作都是本地执行
因为在本地磁盘就有项目的完整历史, 所以大部分操作看起来瞬间完成, 少了集中式版本控制的网络延时开销. 所以离线也能工作, 提交, 等到有网络时再上传.
Git 保证完整性
Git 中所有数据在存储前都计算校验和, 然后以校验和来引用. 这意味着不可能在 Git 不知情时更改任何文件内 容或目录内容. 这个功能建构在 Git 底层, 是构成 Git 哲学不可或缺的部分. 若你在传送过程中丢失信息或损坏 文件, Git 就能发现.
Git 用以计算校验和的机制叫做 SHA-1 散列 (hash, 哈希). 这是一个由 40 个十六进制字符(0-9 和 a-f) 组 成字符串, 基于 Git 中文件的内容或目录结构计算出来. SHA-1 哈希看起来是这样:
24b9da6552252987aa493b52f8696cd6d3b00373
实际上, Git 数据库中保存的信息都是以文件内容的哈希值来索引, 而不是文件名.
Git 一般只添加数据
你执行的 Git 操作, 几乎只往 Git 数据库中增加数据. 很难让 Git 执行任何不可逆操作, 或者让它以任何方式清 除数据. 同别的 VCS 一样, 未提交更新时有可能丢失或弄乱修改的内容; 但是一旦你提交快照到 Git 中, 就难 以再丢失数据, 特别是如果你定期的推送数据库到其它仓库的话.
三种状态
Git 有三种状态, 你的文件可能处 于其中之一: 已提交 (committed), 已修改(modified) 和已暂存(staged). 已提交表示数据已经安全的 保存在本地数据库中. 已修改表示修改了文件, 但还没保存到数据库中. 已暂存表示对一个已修改文件的当前 版本做了标记, 使之包含在下次提交的快照中.
由此引入 Git 项目的三个工作区域的概念: Git 仓库, 工作目录以及暂存区域.
指令
- > Git clone [url] // 克隆仓库
- > Git init // 创建. Git 子目录, 包含初始化 Git 仓库的所有必须文件
- > Git add . // 跟踪文件, 把工作区的所有变化提交到暂存区
- > Git commit -m "" // 提交
- > Git status // 检查当前文件状态
- > Git diff // 比较工作目录中当前文件和暂存区快照之间的差异
- > Git commit -a // 跳过暂存区直接将已跟踪文件提交, 不推荐
- > Git rm xx.xx // 从暂存区移除, 且从工作目录中删除
- > Git mv file_from file_to // 文件移除 / 改名</pre>
查看提交历史
- > Git log -p // 显示每次提交的差异
- > Git log --stat // 显示提交的简略统计信息
- > Git log --pretty=oneline // 一行显示
- ...... // 还可以按照时间显示, 控制显示格式等等
撤销操作
- > Git commit --amend // 重新提交
- > Git reset --soft [commit-id] // 回退到某个版本, 只回退 commit 信息
- > Git reset HEAD <file> // 回退提交和暂存, 相当于 Git reset --mixed
- > Git reset --hard [commit-id] // 回退提交, 暂存和工作目录
- > Git checkout -- <file> // 撤销对某个文件的修改, 很危险! 做的任何修改都会消失
- ...... // 删除的分支和用 --amend 覆盖的提交也可以恢复
远程仓库
- > Git remote // 列出你指定的每一个远程服务器的简写. 如果已经克隆了自己的仓库, 那么至少应该能看到 origin- 这是 Git 克隆的仓库服务器的默认名字
- > Git remote -v // 显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL
- > Git remote add hbl [url] // 添加新的远程 Git 仓库, 可以在命令行中使用 hbl 字符串代替 url
- > Git fetch [remote-name] // 从远程仓库拉取数据到本地仓库, 并不会自动合并, 需要手动合并
- > Git push [remote-name] [branch-name] // 如将 master 分支推送到 origin 服务器
- > Git remote show origin // 查看某一个远程仓库的更多信息
- > Git remote rename hbl hbl2 // 修改一个远程分支的简写名
- > Git remote remove hbl2 // 移除一个远程仓库
打标签
以示某次提交的重要, 比如标记发布节点(v1.0)
- > Git tag // 列出标签
- > Git tag -l 'v1.8.5*' // 查找特定标签
- > Git tag -a v1.4 -m 'my version 1.4' // 创建一个附注标签.-m 选项指定了一条将会存储在标签中的信息. 如果没有为附注标签指定一条信息, Git 会运行编辑器要求你输入信息.
- > Git show v1.4 // 显示标签信息与对应的提交信息
- > Git tag -a v1.2 9fceb02 -m "" // 为某次提交打标签
- > Git push origin v1.5 // 默认情况下, Git push 命令并不会传送标签到远程仓库服务器上. 在创建完标签后你必须显式地推送标签到 共享服务器上
- > Git push origin --tags // 这将会把所有不在远程仓库 服务器上的标签全部传送到 origin
- > Git checkout -b version2 v2.0.0 // 在特定的标签上创建一个新分支, 当然, 如果在这之后又进行了一次提交, version2 分支会因为改动向前移动了, 那么 version2 分支就会和 v2.0.0 标签稍微有些不同, 这时就应该当心了.
- > Git config --global alias.co checkout
- > Git config --global alias.br branch
- > Git config --global alias.ci commit
- > Git config --global alias.st status
- $ Git add README test.rb LICENSE
- $ Git commit -m 'The initial commit of my project'
- > Git branch hbl3 // 创建一个分支 hbl3
- > Git checkout hbl3 // 切换到 hbl3 分支
- > Git checkout -b hbl3 // 上面两个操作的合并操作
- > Git log --oneline --decorate --graph --all // 查看项目分叉历史
- > Git checkout master
- > Git merge hotfix // 合并 hotfix 分支到 master 分支. 若有冲突需手动解决, 然后 Git add . 暂存后 Git 就会将它们标记为冲突已解决
- > Git pull // 相当于执行上面两个指令
- > Git branch -d hotfix // 删除本地分支
- > Git push origin --delete serverfix // 删除远程分支. 这个命令做的只是从服务器上移除这个指针. Git 服务器通常会保留数据一段时间直到垃圾回收运行, 所 以如果不小心删除掉了, 通常是很容易恢复的.</pre>
- > Git fetch origin // 抓取远程仓库有而本地没有的数据
- > Git push (remote) (branch) // 推送到远程仓库
- > Git checkout -b hbl2 origin/hbl2 // 创建一个本地分支跟踪远程分支
- > Git checkout --track origin/serverfix // 与上述写法等效
- > Git branch --set-upstream-to origin/serverfix // 已有本地分支, 跟踪远程分支或修改上游分支
- > Git branch -vv // 查看设置的所有跟踪分支
- // 新建一个空目录
- > Git init // 生成一个隐藏目录. Git, 里面有很多文件, 就是控制和管理版本库的
- > Git remote add origin [url] // 添加远程仓库
- > Git fetch origin // 获取数据
- > Git checkout -b hbl2 origin/hbl2 // 跟踪远程分支, 参考上述 3 种写法
- > Git checkout hbl2
- > Git rebase master // 当前分支 experiment, 变基操作的目标基底分支 master
- > Git checkout master
- > Git merge experiment // 合并
- > Git commit-squash --fetch --message ""
- > Git push -f
- > Git clone SSH://user@server/project.Git // 通过 SSH 协议克隆版本库, 可以指定一个 SSH:// 的 URL
- > Git clone user@server:project.Git // 另一种简单的写法. 也可以不指定用户, Git 会使用当前登录的用户名.
- // 创建一个空目录
- > Git init hbl-repositry // 目录下会生成一个仓库文件夹 hbl-repositry, 其中包含隐藏目录. Git
- > Git clone --bare hbl-repositry hbl-repositry.Git // 把现有仓库导出为裸仓库, 里面的内容是 .Git 里的内容. 即取出 Git 仓库自身, 不要工作目录, 然后特别为它单独创建一个目录.
- // 本地执行
- > scp -r hbl-repositry.Git root@192.168.8.112:~/hbl/Git // 假设服务器上存在 /hbl/Git/ 目录, 复制裸仓库来创建一个新仓库
- > Git clone root@192.168.8.112:~/hbl/Git/hbl-project.Git // 其他通过 SSH 连接这台服务器并对 /opt/Git 目录拥有可读权限的使用者, 通过该命令就可以克隆你的仓库.
- // 服务器上执行
- > Git init --bare --shared// 如果到该项目目录中运行 Git init 命令, 并加上 --shared 选项, 那么 Git 会自动修改该仓库目录的组权限为可写.
- > Git reflog // 引用日志, 保存在本地, 记录了最近几个月的 HEAD 和分支引用所指向的历史
- > Git show HEAD^ // 祖先引用, 查看 HEAD 的父提交
- > Git show HEAD~ // 与上述引用等价
- > Git show d921970^2 // 代表 "d921970 的第二父提交" 这个语法只适用于合并 (merge)的提交, 因为合并提交会有多个父提交. 第一父提交是你合并时所在分支, 而第二父提交是你所合并的分支.
- > Git show d921970~2 // 表示第一父提交的第一父提交 等价于 Git show d921970^^
- > Git log master..experiment // 显示在 experiment 分支中而不在 master 分支中的提交
- > Git log origin/master..HEAD // 查看即将推送到远端的内容. 这个命令会输出在你当前分支中而不在远程 origin 中的提交. 如果你执行了 Git push 并且你的当前分支正在跟踪 origin/master,Git log origin/master..HEAD 所输出的提交将会被传输到远端服务器. 如果你留空了其中的一边, Git 会默认为 HEAD. 例如, Git log origin/master.. 将会输出与之前例子相同的结果.
- > Git log refA refB --not refC // 查看所有 被 refA 或 refB 包含的但是不被 refC 包含的提交
- > Git stash // 项目中改动了几个文件, 其中一些放在了储藏区, 然后想切换分支但又不想提交之前的工作, 就需要储藏修改, 将储藏推送到栈上, 不会储藏未跟踪文件
- > Git stash --include-untracked // 储藏包括未跟踪文件
- > Git stash list // 查看储藏列表
- > Git stash apply // 应用储藏, 但是之前暂存到文件不会重新暂存
- > Git stash apply stash@{
- 2
- } // 应用某个储藏
- > Git stash apply --index // 重新应用暂存的修改
- > Git stash drop // 移除储藏
- > Git clean // 清理工作目录, 移除未被跟踪的文件, 慎用!!!!
- > Git stash --all // 移除每一样东西并存放在栈中
- > Git grep -n gmtime_r // 默认情况下 Git 会查找你工作目录的文件. 可以传入 -n 参数来输出 Git 所找到的匹配行行号
- > Git grep -p gmtime_r *.c // 想看匹配的行是属于哪一个方法或者函数
- > Git log -SZLIB_BUF_MAX --oneline //Git 日志搜索, 想找到 ZLIB_BUF_MAX 常量是什么时候引入
- > Git commit --amend // 重新提交
- > Git filter-branch --tree-filter 'rm -f passwords.txt' HEAD // 从每一个提交移除一个文件
- > Git merge -Xignore-space-change whitespace // 忽略所有空白修改
- > Git reset --hard HEAD~ // 撤销合并
- > Git submodule add [url] // 添加一个子模块, 会产生一个新的 .gitmodules 文件, 该配置文件保存了项目 URL 与已经拉取的本地目录之间的映射
- > Git submodule update // 从子模块仓库中抓取修改时, Git 将会获得这些改动并更新 子目录中的文件, 但是会将子仓库留在一个称作 "游离的 HEAD" 的状态. 这意味着没有本地工作分支 (例如 "master") 跟踪改动. 所以你做的任何改动都不会被跟踪.
- > Git bundle create repo.bundle HEAD master // 就会有一个名为 repo.bundle 的文件, 该文件包含了所有重建该仓库 master 分支所需的数据. bundle 命令会将 Git push 命令所传输的所有内容打包成一个二进制 文件, 你可以将这个文件通过邮件或者闪存传给其他人, 然后解包到其他的仓库中. 如果你在打包时没有包含 HEAD 引用, 你还需要在命令后指定一个 - b master 或者其他被引入的分支, 否则 Git 不知道应该检出哪一个分支.
- > Git clone repo.bundle repo // 使用
来源: http://www.jianshu.com/p/a7b9aaf72692