1. git使用简介
1.1 git的配置文件
三级配置文件
项目级
.git/config
git config user.name 'username'
用户级
~/.gitconfig
git config —global user.name 'username'
系统级
/etc/gitconfig
git config —system user.name 'username'
初始化的git配置
- 用户名 & 邮箱
git config user.name 'username'
git config user.email 'email@xxx.xxx'
- 是否忽略文件权限变化
git config core.filemode false
- 编辑器的配置
// 设置编辑器
git config core.editor vim
// 合并工具
git config merge.tool
// 设置diff工具
git config --global diff.tool vimdiff
git config --global difftool.prompt No
- 着色
git config --global color.ui true
// git branch/diff/status 着色
git config --global color.status auto
git config --global color.diff auto
git config --global color.branch auto
将git commit 编辑器改为vim
- 编辑
.git/config
文件。在core
中添加editor = vim
。如此以后在使用git的时候就自动使用vim作为编辑器 - 除去git,系统中有其他的也会调用编辑器,可以使用一下命令来全局配置编辑器的选择:
- 编辑
update-alternatives --config editor
git config --global core.editor vim
sudo update-alternatives --config editor
- 本地分支绑定远程分支
如果你最近更新了 Git,你可能会在执行 git push 时看到如下消息:
warning: push.default is unset; its implicit value is changing in
Git 2.0 from 'matching' to 'simple'. To squelch this message
and maintain the current behavior after the default changes, use:
git config --global push.default matching
To squelch this message and adopt the new behavior now, use:
git config --global push.default simple
- Matching
matching
参数是 Git 1.x 的默认行为,其意是如果你执行 git push 但没有指定分支,它将 push 所有你本地的分支到远程仓库中对应匹配的分支。
- Simple
而 Git 2.x 默认的是 simple
,意味着执行 git push 没有指定分支时,只有当前分支会被 push 到你使用 git pull 获取的代码。
修改默认设置
从上述消息提示中的解释,我们可以修改全局配置,使之不会每次 push 的时候都进行提示。对于 matching 输入如下命令即可:
git config --global push.default matching
而对于 simple ,请输入:
git config --global push.default simple
1.2 配置私钥
需要配置自己的私钥. 在 ~/.ssh/id_rsa
文件, 此文件的权限必须是 0600
ssh
可以通过-i
使用指定的私钥文件,如:
ssh -i ~/mykey_rsa username@host
但是走ssh协议
的git
却没有类似的参数可以指定,只能是使用用户默认的ssh私钥
。
如果要在git
中使用特定的ssh key
文件,可以在.ssh/config
中增加一个host
配置,格式如:
host 名称(自己决定,方便输入记忆的)
hostname 主机名
port 端口
user 登录的用户名
Identityfile 私钥文件路径
例如添加一个github的配置:
host mygithub
user git
hostname github.com
port 22
identityfile ~/.ssh/id_rsa_git
之后就可以使用mygithub
这个名字来代替git url
里git@github.com
部分了。
ssh -T mygithub /*测试配置*/
git clone ssh://mygithub:{gitusername}/{projectname}.git /*{gitusername}部分是github的username。 */
1.3 管理代码
如果在服务器已经部署你的公钥了, 那么你可以尝试从服务器上checkout代码了
git clone git@***.git
git clone git@***.git dirname // [将代码检出到dirname目录下]
cd dirname
git branch // 查看当前所在分支名
git checkout –b new_branch [target_branch] // 创建new_branch并切换至new_branch分支, target_branch默认当前分支
git checkout target_branch // 切换至target_branch, target_branch不存在会报错(首先保证当前分支上没有改动, 才能进行切换)
git fetch origin // 获取远程所有有改动的分支
git merge origin/target_branch // 合并origin/target_branch分支代码至当前分支
git pull origin target_branch // 从远程 target_branch 分支拉代码
# 我想知道本次就那些文件进行过修改(我想确定分支上有没有修改)
git status
# 我想对比一下, 看看我到底进行了那些操作?
## 没有用git add
git diff
git difff origin/master #跟远程的master对比
git diff origin/remote_branch #跟远程***_branch对比
## 已经使用过git add
git diff --cached
# 我修改之后,想放弃此次修改
git checkout xx_filename
git stash
# 将自己的改动推到远程
git push origin current_branch
1.4 储藏
我的分支上有改动,但是我还想切换分支, 但我又不想提交我的改动, 使用 git stash
将改动储藏起来
- 想要看我的储藏列表
git stash list
- 想要应用储藏的内容
git stash apply –index
(索引位置) - 想要查看我具体储藏了那些内容
git stash list -p
- 删除储藏列表
gitstash drop
储藏名 - 想要查看此次储藏的涉及到那些文件?
git stash show stash:{0}
查看名为stash{0}缓存的文件列表
注意: stash 尽量少用,最好只缓存一次,不然顺序会搞不好弄乱的。
1.5 冲突
如果在 git merge
或 git pull
时, 发生冲突, 如果这些冲突是自己的原因产生的, 那么自己解决, 但是如果不是自己的原因, 那可以查看文件的日志(命令如下), 找到冲突的文件曾被谁更改过, 之后一起解决冲突
git log [–p ] // 文件名【-p可省略, 加上-p显示的是详细信息】
还有一种就是, 如果冲突的文件中没有新内容, 并且你可以找到一个最新的版本
例如: index.php
在master
上面是最新的, 而在本地冲突了, 但是你不想解决这个冲突, 可以执行以下操作(慎用, 执行完之后你自己的代码没有保留也没有备份)
git add index.php
git reset HEAD index.php //【慎用】
git checkout origin/master index.php
这样以后index.php就跟远程的master分支上一致了。
1.6 代码回退
git reset
回退以前某个版本git reset
是指将当前head的内容重置,不会留log信息。
git reset HEAD filename // 从暂存区中移除文件
git reset --hard origin/master // 将代码重置到origin/master
git reset --hard HEAD~3 // 会将最新的3次提交全部重置,就像没有提交过一样。
git reset --hard commit (38679ed) // 回退到 38678ed 版本
根据–soft –mixed –hard,会对working tree和index和HEAD进行重置
命令模式 | 命令介绍 | 对比差异 | 备注 |
---|---|---|---|
git reset --mixed xxx | 此为默认方式,不带任何参数的git reset,即时这种方式,它回退到某个版本,只保留源码,回退commit 和index 信息 | git diff | 开发过程中的代码 --mixed 后上一次的代码还在 |
git reset--soft xxx | 回退到某个版本,只回退了commit 的信息,不会恢复到index file一级。如果还要提交,直接commit 即可 | git diff --cached | 本地缓冲区 --soft 后上一次的代码还在 |
git reset --hard xxx | 彻底回退到某个版本,本地的源码也会变为上一个版本的内容 | – | 本地代码库 --hard 后上一次的代码不在, 不能恢复 |
1.7 差异(diff)
比较两个分支的差异
git diff master...version_no/branch (3个点可以比较任意不同)
git diff A..B B里面有而A没有的改变(2个点)标签biaoqian
git diff HEAD //与上次 commit 之间的差别(爸爸)
git diff HEAD^ //与上上次(爷爷)
git diff HEAD^^ //与上上上次(曾祖父)
git diff HEAD~5 //与前面第5次commit(好吧…祖先吧)
git diff HEAD^..HEAD //中间是两个点比较(爸爸)和(爷爷)的差别
git diff hash1..hash2 //比较 两个不同 hash 值记录之间的不同
git diff master dev //比较 branch 之间的不同
git diff --since=1.week.ago --until=1.minute.ago //还可以根据时间来比较哦
1.8 日志(log)
# 获取当前版本号
git log --pretty -1 | awk '/^commit/{print $2}'
# 默认 git log 样式不太好看,换成一个比较好看的
git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset'
git log --pretty --oneline在一行显示 git log.
git log --oneline --stat ,显示每个文件的变化行数, --start参数是用来统计哪些文件被改动,有多少行被改动。
git log --oneline --graph,则可以图形化地显示 branch 的变化(方便查看 merge 变化)。
git log --until=1.minute.ago // 一分钟之前的所有 log
git log --since=1.day.ago //一天之内的log
git log --since=1.hour.ago //一个小时之内的 log
git log --since=1.month.ago --until=2.weeks.ago //一个月之前到半个月之前的log
git log --since ==2013-08.01 --until=2013-09-07 //某个时间段的 log
git log –stat –summary 查看每个版本变动的档案和行数
/**
* %ad author date // 日期
* %an author name // 作者名
* %cn committer name //提交者姓名
* %h SHA hash // hash值
* %s subject //commit的描述
* %d ref names //对应的 branch 分支名
*/
git log --pretty=format:"%h %ad- %s [%an]"
1.9 忽略文件
# 执行命令
git config core.excludesfile
# 修改 .gitignore
# 修改 .git/info/exclude
git update-index --assume-unchanged database.php // 忽略在库中的文件的改变
# 添加一个忽略文件到 gitignore
git rm --cached your_ignored_file
1.10 标签管理(tag)
# 查看tag
$ git tag | grep dev
# 创建tag
$ git tag dev -m 'add dev tag'
# 把tag push到远程
$ git push origin dev
$ git push origin --tags
# 删除tag 本地删除
$ git tag -d dev
# 删除远程的tag:推一个空的上去 (有的gitlab没有删除远程tag的权限)
$ git push origin :refs/tags/dev
2. git代码合并方法总结
前面我们在管理代码时介绍了通过pull
和merge
合并代码, 在这里介绍git cherry-pick
和 git rebase
2.1 git merge
- 用来合并两个分支的。
# 将b分支合并到当前分支
git merge branch
2.2 git cherry-pick
可以选择某一个分支中的一个或几个commit(s)来进行操作。
例如,假设我们有个稳定版本的分支,叫v2.0,另外还有个开发版本的分支v3.0,我们不能直接把两个分支合并,这样会导致稳定版本混乱,但是又想增加一个v3.0中的功能到v2.0中,这里就可以使用cherry-pick了。
## 先在v3.0中查看要合并的commit的commit id
git log
# 假设是 commit f79b0b1ffe445cab6e531260743fa4e08fb4048b
# 切到v2.0中
git check v2.0
# 合并commit
git cherry-pick f79b0b1ffe445cab6e531260743fa4e08fb4048b
2.3 git rebase
- 类似git merge
但是两者又有不同,打个比方,你有两个抽屉A和B,里面都装了衣服,现在想把B中的衣服放到A中,
git merge是那种横冲直撞型的,拿起B就倒入A里面,如果满了(冲突)再一并整理;
而git rebase就很持家了,它会一件一件的从B往A中加,会根据一开始放入的时间顺序的来加,如果满了你可以处理这一件,你可以继续加,或者跳过这一件,又或者不加了,把A还原。
所以merge适合那种比较琐碎的,简单的合并,系统级的合并还是用rebase吧。
@TODO: 专业的区别请移步到这里合并和衍合
# 合并b
git rebase branch
# 处理完冲突继续合并
git rebase --continue
# 跳过
git rebase --skip
# 取消合并
git rebase --abort
变基
整合不同分支的修改主要方式: merge
和 rebase
merge
将两个分支的最新快照, 以及共同的祖先进行三方合并, 生成一个新的快照并提交rebase
提取在dev上引入的补丁和修改, 然后在master的基础上再应用一次. 就像”重新播放”一样, 将dev上的所有改动都移至master分支.rebase
原理: 首先找到master/dev共同的祖先, 然后对比两个分支的历次提交, 提取相应的修改并存为临时文件. 并按照原有次序依次应用到另一分支. rebase
风险: 不要对在你的仓库外有副本的分支执行变基. 变基实质是丢弃一些现有的提交, 然后相应的新建一些内容一样单实际上不同的提交.
2.4 变基(rebae) vs 合并(merge)
对尚未推送//分享给别人的本地修改执行变基操作清理历史, 从不对已推动至别处的代码执行变基操作.
git merge
- 横冲直撞式的合并
git rebase
- 类似于git merge
- 温文尔雅式的合并
- 依据提交的时间顺序来合并
2.5 多出来的commit
Git从将远程分支与本地分支合并可以有两种方式,一种是 git pull
, 另一种是 git fetch
+ git rebase
.
区分在于 git pull
是把远程分支代码拉下来,与本地分支进行merge
操作,相当于git fetch
+ git merge
所以使用git pull
命令之后,会自动多出来一次 merge
的commit
,从git log
上面看到的情况就是多了一次commit
, 而且git树也不那么整洁了。
推荐的做法是使用rebase
而不是pull
, 可以git fetch
; git rebase
,也可以git pull —rebase
.