介绍
Git是一个软件版本控制管理的一种机制和实现,类似的还有:SVN, Mercurial;更详细的可以参见维基百科的list of version control software 。
不同于SVN,Git是一种分布式的版本控制系统。最初是Linus Torvalds 为了用于管理Linux内核而在2005年开发的,2008年建立的Github网站则使得git系统日益流行。
代码托管网站
- GitHub
- GitLab
- BitBucket
- 码云Gitee.com (开源中国, CSDN)
- 扣钉 Coding.net
Git基础
Git主要特点:
- 分布式:每个主机上保存的仓库副本都有完整的记录
- 快照记录而非差异比较:类似文件系统的方式,每次提交更新都是对全部文件制作一个快照并保存快照的缩影
- 主要操作是本地执行
Git尽管是分布式的结构,但在团队协作中,通常会在服务器中建立一个仓库作为(准)中心。因此Git中存在远程仓库(比如在服务器中)和本地仓库(当前工作环境):
- 远程仓库也叫上游仓库(upstream repostory),可以看做版本的最终状态。
- 本地环境有四部分组成:工作区(workspace,程序和资源区域)、本地仓库(local repository,隐藏目录.git)、索引区(Index,也叫缓存区)、隐藏区(stash)。
- 工作区中存放的实际操作的文本文件等资源。
- 本地仓库保管你索引提交的记录,其中HEAD指向最后一次(最新)commit的引用。
- 索引区类似缓存区域,临时保存改动的内容。
- 隐藏区主要用于当你需要切换到另一个分支是,暂时保存目前的工作状态(可能有修改没有提交或完成),隐藏目前修改内容等。
其中.git
目录中的内容
- objects目录:存储hash记录,第一层目录是sha1哈希的前两位;第二层目录是sha1哈希的后38位,里面的文件已经压缩
- config文件:项目的配置文件,优先级高于用户目录.gitconfig
- refs目录:heads中是分支名, tags中是标签名, 文件中是hash编码
-HEAD文件: 包含当前分支的引用
安装和配置
安装git
Git的官网是https://git-scm.com,可以下载对应系统的git软件。
- Linux中安装
# fedora/centos, 使用yum或dnf
sudo yum install git
# debian/ubuntu, 使用apt或apt-get
sudo apt-get install git
-
Windows安装,下载地址
- https://git-scm.com/download/win
- 此外还有git for windows的项目(http://msysgit.github.io/, https://gitforwindows.org/)
macOS: http://git-scm.com/download/mac
此外也可以直接使用GitHub Desktop(适合Windows和Mac),Linux有非官方版本。另外,图形界面的管理软件参见,推荐有 SourceTree。
基础配置
- 配置本地git用户(全局)
$ git config --global user.name "yourname"
$ git config --global user.email "yourname@email"
说明:必须配置用户名和邮箱信息后才能提交改动信息,--global
表示全局(保存在用户路径/.gitconfig
文件中),否则用户名和邮箱只在当前仓库有效(保存在项目仓库的。.git/config
)。
- 设置行尾首选项
- 配置别名,便于使用
$ git config --global alias.
- 配置编辑器(默认是vim)
$ git config --global core.editor
- 查看所有配置信息
$ git config --list
- 修改配置文件.gitconfig:
$ git config --global --edit
说明:配置文件包括:
/.git/config 仓库级别(优先级最高) /.gitconfig 用户级别(优先级次之),设置时添加参数 --global
- /etc/gitconfig 系统级别(优先级最低),设置时添加参数
--system
远程仓库协作
- 配置SSH密钥(可以避免在上传或拉取代码时输入密码;使用少数可信小团体;权限设置有限)
# 1. 生成SSH Key
$ ssh-keygen -t rsa -C "yourname@email" # 简单的话默认回车
# 2. 将密钥添加到远程服务器端, rsnyc或scp或ssh-copy-id 三选一()
$ rsync -av ~/.ssh/id_rsa.pub username@remote:~/.ssh/authorized_keys
$ scp ~/.ssh/id_rsa.pub username@remote:~/.ssh/authorized_keys
$ ssh-copy-id -i ~/.ssh/id_rsa.pub username@remotet
说明:生成的SSH Key在用户目录下的.ssh目录中,包括id_rsa(私钥文件,绝对不能泄露),id_rsa.pub(公钥文件)
- 建立本地git仓库,并上传
$ cd local-project
$ git init
$ git add .
$ git commit -m "initial commit"
$ git remote add origin ssh://username@remote-ip/absolute-path/myrepo.git
$ git push origin master # 上传代码
$ git pull origin master # 拉取代码(更新本地)
- ssh:// 表示使用ssh协议连接并传输(常用的还有https和git协议)
- username是服务器仓库所在的用户,如git-name
- remote-ip局域网中服务器的IP地址,如192.168.0.111
- absolute-path是仓库所在绝对路径,如/home/git/;也可以使用~等方式表示用户主目录
- myrepo.git是服务器中所建立的仓库名
- 获取远程项目并协作
$ git clone [git-repo url] local-reponame
$ ... 操作修改并提交更新
$ git push origin master
local-reponame 是本地仓库的名字,可以为空(目录会自动生成不需要建立,默认为远程仓库名mygrepo,自动忽略.git后缀)
Git基础操作
获得git仓库
一种方式是现有项目初始化
$ git init # 将当前目录转为仓库
$ git init # 目录可以不存在
$ git init --bare repo-name.git # 建立一个裸的仓库
说明:
git init
建立一个新的git仓库,在目录中会有一个.git的目录(隐藏状态)。它可以建立一个空的新仓库或将当前已存在的项目转成git仓库用于版本控制。
--bare
裸仓库的作用:
裸仓库中没有工作区,不作为开发环境,一般用于服务器中,且不存放实际文件资源,通常以git作为后缀。
或者,克隆现有仓库,其中仓库地址URL可以使http协议的、git协议、ssh协议等或者本地文件系统路径
# 基本形式是git clone [url]
$ git clone /path/repo-name # 克隆本地仓库,并使用默认名字
$ git clone # 克隆仓库并使用指定目录名字(会建立一个目录)
$ git clone username@host:/path/repo-name # 远程使用SSH
$ git clone https://path/repo-name # HTTPS协议
$ git clone git:/path/repo-name # git协议
注:克隆仓库是,如果远程仓库是.git作为后缀,会忽略,只有前面一部分作为仓库名。
提交更新
仓库中文件状态通常有:
- Untracked files:
- Changes not staged for commit:
- Changes to be committed:
- Unmerged paths:
git status查看文件状态,主要指工作区中未缓存的文件和索引区未提交的文件,包括修改的、新添加的、删除的
$ git status
**git add **将工作区文件添加的索引区,同时进行跟踪文件:(提交前的多次索引区域修改会合并)
$ git add # 添加某个文件
$ git add * # 所有文件
$ git add . # 当前目录所有文件
git rm移除文件
# 移除/删除文件,并从暂存区移除相关追踪
$ git rm
# 普通的删除,显示状态为`Changes not staged`
$ rm
git mv移动文件或改名
$ git mv README.txt README
# 等价于以下三条命令
$ mv README.txt README
$ git rm README.txt
$ git add README
git commit将改动信息提交到仓库
$ git commit -m "message" # 提交信息一般而言是必须的
$ git commit --amend # 合并到上一次提交(会替换为新快照)或修改上一次提交的信息(索引区区没有内容缓存)
$ git commit # 进入编辑页面,输入相关信息保存后会提交
$ git commit -a -m "message" # 直接暂存(-a包括了git add步骤)并提交
如果仅使用git commit会显示一个输入提交信息,可以输入多行说明信息,适合较大的改动。一般格式:第一行是总结性说明(一般50字符以内),空一行,就下来是具体更改的说明(很多开发者采用一般现在时态)
$ git commit提交的是索引区的缓存的快照,对于工作区的内容不干预
git diff查看文件修改
$ git diff --cached
$ git diff --staged # 1.6.1版本以上
git log历史/日志
查看仓库中已提交的历史记录(可以使用以下图形化的工具如gitk)。记录较多时,仅显示最新的记录,空格或回车或箭头等翻页,Q键退出。常见的参数有:
$ git log -n # 仅显示最新的个
$ git log --oneline # 显示一行的简略信息
$ git log --stat # 额外显示提交增删改变
$ git log -p # 额外显示每次提交的文件差异
$ git log --grep="" # 筛选特定信息的提交
$ git log --graph --oneline # 图形化显示且一行
$ git log --pretty=oneline
注意:git log显示信息说明
第一行 commit后的40个字符是提交信息的SHA-1的校验和,用于保证提交的正确性,作为提交的唯一标识(ID)
第二行是提交人的用户名和邮箱
第三行是提交日期
空一行之后是提交时填写的说明信息。
撤销管理或修改
撤销修改
- 暂存前,仅本地修改:git checkout filename
- 已经暂存(git add): git reset HEAD filename;
其中:reset 命令重置 HEAD 中暂存区的内容。这将清除我们已经暂存 的更改。 - 已经提交:git revert HEAD (--no-edit) 会进入一个信息编辑页面
Revert 撤销当前修改,回到HEAD版本(通常是上一个),但实际的提交记录仍然存在
移除提交,使用git reset重置, git log查看会看到撤销的提交,
git reset --hard [tag-name/branch-name/hash-code]
说明:提交信息实际仍然存在,除非使用hash-code进行引用(可从.git目录查看相关记录);另一种方式是预先使用tag做标记,这时使用git log --all仍可以发现那些撤销的提交,标签删除后,相关提交记录也会看不到
修正提交: git commit --amend -m ""
忽略文件
对某些不需要加入git管理,如程序中编译中的中间文件等,建立.gitignore
文件进行设定。通常可使用通配符表示需要忽略的文件或目录。
来自git pro的例子
# 此为注释 – 将被 Git 忽略
# 忽略所有 .a 结尾的文件
*.a
# 但 lib.a 除外
!lib.a
# 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
/TODO
# 忽略 build/ 目录下的所有文件
build/
# 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目录下所有扩展名为 txt 的文件
doc/**/*.txt
远程同步
git remote管理远程仓库
git remote
用于添加、查看和移除你当前仓库与其他仓库的连接,常用一个别名(如origin
)代替远程仓库的URL。
Git版本管理中每个本地仓库是相互隔离的,信息是不共享,需要手动将上游仓库拉取(pull)到本地,手动将本地提交推送(push)到远程/中央仓库。
查看
$ git remote # 查看所连接的远程仓库
$ git remote -v # 和上个命令相同,同时显示连接的URL(v==verbose)
# 添加远程仓库(URL表示)的,之后可使用表示远程仓库
$ git remote add
# 移除
$ git remote remove
# 重命名
$ git remote rename
# 查看远程仓库信息
$ git remote show origin
讨论:
origin
远程连接:使用git clone
时默认会建立名为origin
的远程连接,方便与远程仓库交互。- 仓库URL: HTTP(HTTPS)是允许匿名但只读,SSH、GIT需要读写。
另:大多数基于 Git 的项目将它们的中央仓库取名为 origin。
git fetch 获取更新
$ git fetch # 获取远程仓库所有分支
$ git fetch # 仅获取特定分支
git pull推送更新到远程仓库
$ git push [remote-name] [branch-name]
$ git push origin master
git merge合并分支
合并
$ git merge
解决冲突:
Automatic merge failed; fix conflicts and then commit the result.
冲突文件中的结构:分成两部分;选择合适内容进行保留,通过一次提交就完成合并了
<<<<<<< HEAD
你的修改
=======
master中的修改
>>>>>>> master
分支和标签
git tag管理标签
Git 使用的标签有两种类型:轻量级的(lightweight)和含附注的(annotated, 使用-a参数)。区别在于轻量级的标签指向特定提交对象的引用(不变),附注型的则是独立对象,可以使用GPG校验。
$ git tag 查看所有标签
$ git tag -l 'v1.4.2.*' # 使用正则匹配某些标签
$ git tag v1 添加标签
$ git tag -a v1.4 -m 'my version 1.4' # 附注标签,-m标签说明信息
$ git tag -d v1 删除标签
更多
$ git checkout v1^(表示v1的父提交,或使用v1~1)
$ git push origin v1.5 # 通常git push不会将标签传送到远程,除非说明
$ git push origin --tags # 推送所有标签
git branch管理分支,分支代表的是独立的开发流水线。
# 列出所有分支,等于git branch --list
$ git branch
# 新建一个分支
$ git branch
# 删除指定分支(如果使用-D用于表示强制删除,包含未合并的更改)
$ git branch -d
# 重命名当前分支名(-m == --move)
$ git branch -m
# 切换到已存在分支上
$ git checkout
# 新建一个分支并切换到新的分支上(如果分支名已存在会报错)
$ git checkout -b
# 以为基新建分支并切换
$ $ git checkout -b
git checkout检出、切换分支/标签/提交等
# 分支切换,如git checkout master
$ git checkout
# commit-id(hash-code)指提交历史中显示40位校验和(通常只需要前7位,可以git log --oneline快速查看)
$ git checkout
# 检出文件(单个或部分文件状态回到过去提交的某一个时刻)
$ git checkout #检出文件
> 这是的工作区的文件状态与时一直;所有的一切不会影响到当前状态。
注意:这里会修改到你的文件内容,变成旧的内容;如果想舍弃旧的回到当前新的内容:
git checkout HEAD
常见问题
error: Your local changes to the following files would be overwritten by checkout: … Please commit your changes or stash them before you switch branches. Aborting
需要先提交/清楚当前仓库中修改的内容
其他命令
- git revert
- git reset
- git rebase
- git reflog
- ...
git服务器和分布式协同
参考Linux中搭建GitLab社区版
其他:
简单的git服务器
git daemon --verbose --export-all --base-path=.
--enable=receive-pack 允许推送(git daemon没有权限管理)
参考资料
- git简明指南(中文):https://rogerdudler.github.io/git-guide/index.zh.html
- 沉浸式学git(git immersion):里面涉及到一些ruby程序,但不影响
• [中文翻译( 2014)]http://igit.linuxtoy.org/), Github仓库
• 英文版, 程序和教程HTML下载(zip文件) - GIT 命令“从初学到专业”完整进阶指南[中文翻译] 2017-12-28
- git教程(阮一峰)
- git-recipes(git中文教程)
- git pro 第二版 中文
其他一些详细的资源列表/收藏
- https://www.jianshu.com/p/25647b9920b7
- https://github.com/dictcp/awesome-git
- https://github.com/hylerrix/awesome-git