Git使用流程及技巧 - 详细教程
前言
Git是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。官方文档链接:Git官方文档 。
本篇文章以GitHub为例,系统为Windows系统。不做特殊说明时,默认为在Git Bash命令行中进行操作,Git Bash软件的下载地址:下载链接 。
内容详细,包含各种初学者可能会遇到的问题和解决方案。既适合初学者,也适合有一定基础的用户。
全部内容包括:Git本地库和远程库的使用流程,IDE集成Git的使用流程,Git GUI使用流程;包括设置SSH key,设置多个SSH key,局域网内搭建Git远程仓库,合并冲突,减少冲突,撤销更改,版本回退,整理提交历史,设置忽略规则(配置.gitignore
文件),配置.gitattributes
文件,使用rebase合并分支,提升SSH传输速度,解决Git Bash命令行的中文乱码问题,解决换行符的替换问题,等等。
1. 技巧
1.1. 基础技巧
- 打开Git命令行:Git Bash的快捷方式或在文件资源管理器中右键Git Bash Here。
- 命令行中的基础操作同Linux命令行,如创建文件夹,Vim命令等。关于Linux的命令行基础命令和用法,详情请参见W3CSchool的教程网站:Linux教程。
- 命令行中的
~
指根目录,即C:\Users\[username]\
。 - 在命令行中进行的全局设置(
git config --global
)保存在根目录下的.gitconfig
文件中,可以使用笔记本进行查看和更改;进行的项目设置(git config
)保存在项目文件夹下的.git/config
文件中。 - 命令行中的文件目录使用符号
/
,例如:D:\Work\Temp
在命令行中要写成d/work/temp
。路径名和文件名不区分大小写,且可以用Tab
进行补全。 - 命令行中,单引号可以代替双引号,但一定要左右匹配,且为英文标点符号。
- 命令行中,若忘记命令的使用方法或
options
,则可以添加-h
参数,查看帮助,如:git remote -h
。 - Git连接远程库有2种方式:HTTPS和SSH(推荐),正文有详细介绍。
- 在整个项目中,项目的文件夹名称,文件名称,Commit Message,Merge Message,等等,尽量不要使用中文。全部用英文较好,否则可能会出现命令行乱码问题。(乱码问题对功能没有影响,但可能会影响项目成员对文件和提交历史的识别)
- 当GitHub仓库的上传文件接口不起作用时,可能是浏览器的兼容问题,可以试试谷歌或火狐浏览器。
- 在GitHub平台的项目仓库中,文件夹名称中可能会出现斜杠符号
/
,众所周知,文件夹名称中不可能包含符号/
,所以该符号表示该文件夹包含的子文件夹。
举一个例子:名称为page/images
的文件夹,代表page
文件夹下的images
文件夹。 - 本篇文章中,所有的
[filename]
都可以用.
代替,代表当前目录所有文件。
1.2. 提升SSH传输速度
在使用 SSH 方式在GitHub上进行代码托管时,一般速度会很慢,可以修改Git软件的配置,即关闭GSS API校验来提升速度,解决方案如下。
解决方案
以Windows 10系统为例:
- 找到Git软件的安装目录,例如:
D:\Program Files\Git
。 - 进入
etc\ssh
目录,找到ssh_config
文件,使用Notepad打开。 - 将
GSSAPIAuthentication no
前面的注释#
删掉,或新增一行GSSAPIAuthentication no
,保存文件。 - 再次使用ssh命令操作GitHub项目,可以体验到速度的提升,本人从
100k/s
变为5M/s
,速度提升50倍。
若无法找到Git软件安装目录,可以右键快捷方式,选择打开文件位置
。
也可以使用vim
命令编辑ssh_config
文件,方法如下:
- 右键文件资源管理器点击
Git Bash here
,打开git命令行。 - 编辑
ssh_config
文件:vim /etc/ssh/ssh_config
。 - 找到
GSSAPIAuthentication no
配置项。 - 配置方法同上。
1.3. 解决Git Bash命令行的中文乱码问题
Windows系统下,Git Bash的中文乱码问题有很多种情况(下方有详细解释),其中一种是计算机内部资源中文乱码(情况1),还有一种是远程库资源乱码(情况2)。这2种乱码不能同时解决,只能选择其一,建议解决情况2,舍弃情况1,因为情况1的需求较小。
建议:
在整个项目中,项目的文件夹名称,文件名称,Commit Message,Merge Message,等等,尽量不要使用中文。全部用英文较好,否则可能会出现命令行乱码问题。(乱码问题对功能没有影响,但可能会影响项目成员对文件和提交历史的识别)
1.3.1. 情况1:内部资源乱码
Windows系统本地的编码为GBK,而在Git Bash中,默认编码不是GBK,所以输出本地中文字符时会显示乱码。
例如:输入systeminfo
,会出现中文乱码,如下图:
解决方案:
命令行窗口右键Options -> Text
界面,Locale
改为zh_CN
,Character set
改为GBK
;点击Apply
和Save
。再输入命令就不是乱码了,如下图:
注意: 情况1和情况2只能解决1种,建议解决情况2。
1.3.2. 情况2:远程库资源乱码(推荐解决)
非git命令
中文显示正常,如:ls
命令,等;但git命令
无法显示中文,如:git status -s
,等。如下图:
解决方案:
命令行窗口右键Options -> Text
界面,Locale
和Character set
为默认值(即空白);或Locale
改为zh_CN
,Character set
改为UTF-8
;点击Apply
和Save
。
并修改全局配置,在Git Bash中输入命令:
git config --global core.quotepath false
注意:
两种情况只能解决一种,建议解决情况2:远程库资源乱码,因为需求较大。
1.3.3. 情况3:GUI界面乱码
在Git GUI界面下可能出现中文乱码。
解决方案:
设置Git GUI的界面编码:
git config --global gui.encoding utf-8
1.3.4. 其他情况:包括Linux
若以上方案均无法解决乱码问题,则可以在Git Bash命令行中尝试以下设置:
git config --global i18n.commitencoding utf-8
git config --global i18n.logoutputencoding utf-8
export LESSCHARSET=utf-8
1.4. 解决冲突的方式和流程(减少冲突)
1.4.1. 主分支解决冲突
- 去自己的工作分支
git checkout work
- 获取最新修改
git pull
- 工作
- 提交工作分支的修改
git commit -m
- 回到主分支
git checkout master
- 获取远程最新的修改,此时不会产生冲突
git pull
- 合并工作分支的修改,若有冲突在此时解决
git merge work
- 推送到远程库
git push
1.4.2. 分支解决冲突(推荐)
在分支解决冲突,可以避免主分支出现冲突问题而造成的代码混乱。
- 去自己的工作分支
git checkout work
- 获取最新修改
git pull
- 工作
- 提交工作分支的修改
git commit -a
- 回到主分支
git checkout master
- 获取远程最新的修改,此时不会产生冲突
git pull
- 回到工作分支
git checkout work
- 合并主干的修改,如果有冲突在此时解决
git merge master
或
git rebase master
(推荐) - 回到主分支
git checkout master
- 合并工作分支的修改,此时不会产生冲突。
git merge work
- 推送到远程库
git push
1.5. 使用rebase整理提交历史或合并分支
1.5.1. 整理提交历史
rebase操作可以把本地未push的分叉提交历史整理成直线;
rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比。
- 将提交历史整理成一条直线
git rebase
- 合并最近的4条提交历史
git rebase -i HEAD~4
这时候,会自动进入 vi 编辑模式:
要注意如下参数:pick ccafe3b rename pick 69683ef new pick b733a55 temp pick fca1d04 txt # Rebase d7865be..fca1d04 onto d7865be (4 commands) # # Commands: # p, pick <commit> = use commit # r, reword <commit> = use commit, but edit the commit message # e, edit <commit> = use commit, but stop for amending # s, squash <commit> = use commit, but meld into previous commit # f, fixup <commit> = like "squash", but discard this commit's log message # x, exec <command> = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with 'git rebase --continue') # d, drop <commit> = remove commit # l, label <label> = label current HEAD with a name # t, reset <label> = reset HEAD to a label # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] # . create a merge commit using the original merge commit's # . message (or the oneline, if no original merge commit was # . specified). Use -c <commit> to reword the commit message. # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out
按照以上参数修改提交记录:# p, pick <commit> = use commit # r, reword <commit> = use commit, but edit the commit message # e, edit <commit> = use commit, but stop for amending # s, squash <commit> = use commit, but meld into previous commit # f, fixup <commit> = like "squash", but discard this commit's log message # x, exec <command> = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with 'git rebase --continue') # d, drop <commit> = remove commit # l, label <label> = label current HEAD with a name # t, reset <label> = reset HEAD to a label # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
修改完查看结果:p ccafe3b rename s 69683ef new s b733a55 temp s fca1d04 txt
git log
1.5.2. 合并分支
git merge
操作合并分支会让两个分支的每一次提交都按照提交时间(并不是push
时间)排序,并且会将两个分支的最新一次commit
点进行合并成一个新的commit
,最终的分支树呈现非整条线性直线的形式。
git rebase
操作实际上是将当前执行rebase
分支的所有基于原分支提交点之后的commit
打散成一个一个的patch
,并重新生成一个新的commit hash
值,再次基于原分支目前最新的commit
点上进行提交,并不根据两个分支上实际的每次提交的时间点排序,rebase
完成后,切到基分支进行合并另一个分支时也不会生成一个新的commit
点,可以保持整个分支树的完美线性。
-
先从 master 分支切出一个
feature1
分支,进行开发
git checkout -b feature
分支树如下图:
-
这时,你的同事完成了一次修改(
hotfix
) ,并合并了master
分支,此时master
已经领先于你的feature1
分支了:
-
此时,我们想要同步
master
分支的改动方法一:merge方法
git(feature1): git merge master
若执行git log
命令,就会在记录里发现一些merge
的信息,但我们想要保持一份干净的commit
。这时候,git rebase
就派上用场了,详情见方法二。方法二:rebase方法
git(feature1): git rebase master
从commit
记录我们可以看出来,feature1
分支是基于hotfix
合并后的master
,自然而然的成为了最领先的分支,而且没有merge
的commit
记录,是不是感觉很舒服了。补充一下
rebase
的原理:
首先, git 会把feature1
分支里面的每个commit
取消掉;
其次,把上面的操作临时保存成patch
文件,存在.git/rebase
目录下;
然后,把feature1
分支更新到最新的master
分支;
最后,把上面保存的patch
文件应用到feature1
分支上; -
在
rebase
的过程中,也许会出现冲突conflict
。在这种情况, git 会停止rebase
并会让你去解决冲突。在解决完冲突后,用git add
命令去更新这些内容。注意,你无需执行
git commit
,只要执行continue
git rebase --continue
这样 git 会继续应用余下的patch
补丁文件。 -
在任何时候,我们都可以用
--abort
参数来终止rebase
的行动,并且分支会回到rebase
开始前的状态。
git rebase --abort
1.6. 设置忽略规则
在使用Git的过程中,我们喜欢有的文件比如日志,临时文件,项目配置文件,编译的中间文件等(如.idea
文件夹,config
文件等)不要提交到代码仓库,这时就要设置相应的忽略规则,来忽略这些文件的提交。
1.6.1. 三种忽略方法
Git 忽略文件提交的方法有三种,忽略规则和语法会在后续提及,并详细介绍方法一,方式如下:
方法一(推荐): 在Git项目中定义 .gitignore 文件
这种方式通过在项目的某个文件夹下(通常在项目根目录下)定义 .gitignore
文件,在该文件中定义相应的忽略规则,来管理当前文件夹下的文件的Git提交行为。
.gitignore
文件是可以提交到共有仓库中的,这就为该项目下的所有开发者都共享一套定义好的忽略规则。
在 .gitignore
文件中,遵循相应的语法,在每一行指定一个忽略规则。
方法二: 在Git项目的设置中指定排除文件
这种方式只是临时指定该项目的行为,需要编辑当前项目下的 .git/info/exclude
文件,然后将需要忽略提交的文件写入其中。
需要注意的是,这种方式指定的忽略文件的根目录是项目根目录。
方法三: 定义Git全局的 .gitignore
文件
除了可以在项目中定义 .gitignore
文件外,还可以设置全局的 .gitignore
文件来管理所有Git项目的行为。这种方式在不同的项目开发者之间是不共享的,是属于项目之上Git应用级别的行为。
这种方式也需要创建相应的 .gitignore
文件,可以放在任意位置。然后在使用以下命令配置Git:
git config --global core.excludesfile ~/.gitignore
1.6.2. gitignore(方法一)使用流程
-
在项目根目录打开Git Bash命令行(即Git Bash Here)。
-
创建
.gitignore
文件touch .gitignore
-
编辑
.gitignore
文件vim .gitignore
示例内容:
# 忽略当前目录的bin文件夹 /bin/ # 忽略当前目录的dir文件 /dir # 忽略所有的test.txt文件 test.txt # 忽略所有的html文件 *.html
-
保存
.gitignore
文件
按Esc
键,然后输入:wq
即可。
1.6.3. 忽略规则配置语法
官方文档链接:gitignore文档 。
#
开头表示注释,可以使用反斜杠进行转义;
/
开头表示当前目录,开头没有/
表示当前目录及子目录的所有匹配项;
/
结尾表示文件夹;
*
匹配多个字符;
**
匹配多级目录,可在开始,中间,结束;
?
匹配单个字符;
[]
包含单个字符的匹配列表;
!
表示追踪(不忽略,即添加)匹配到的文件或目录。
注意: git 对于 .gitignore
配置文件是按行从上到下进行规则匹配的。gitignore还可以指定要将哪些文件添加到版本管理中:唯一的区别就是规则开头多了一个感叹号,Git会将满足这类规则的文件添加到版本管理中;添加规则通常与其他忽略规则配合使用,以达到只添加一个文件夹中某一文件的效果。
1.6.4. 忽略规则优先级
在 .gitingore
文件中,每一行指定一个忽略规则,优先级按行从上到下;Git 检查忽略规则的时候有多个来源,它的优先级如下(由高到低):
从命令行中读取可用的忽略规则;
当前目录定义的规则;
父级目录定义的规则,依次地推;
$GIT_DIR/info/exclude
文件中定义的规则;
core.excludesfile
中定义的全局规则。
1.6.5. 忽略规则不生效
.gitignore
只能忽略那些原来没有被track
的文件,如果某些文件已经被纳入了版本管理中(即创建.gitignore
文件之前就push
了某一文件),那么即使你在.gitignore
文件中写入过滤该文件的规则,该规则也不会起作用,git仍然会对该文件进行版本管理。
解决方法就是先把本地缓存删除(改变成untrack
状态),然后再提交。(注意: 删除缓存后,合并分支时,本地文件可能会同步消失,所以在删除缓存前,建议先把要忽略的文件备份一下,防止文件丢失;若文件不重要,可有可无,则不必备份。)
删除本地缓存的命令如下:
删除所有文件
git rm -r --cached .
删除文件夹
git rm -r --cached [dirname]
删除某一文件
git rm --cached [filename]
提交命令如下:
git add .
git commit -m "update .gitignore"
1.6.6. 忽略规则示例
说明
下文提到的当前目录
指:.gitignore
文件所在的目录。
常用规则
规则 | 作用 |
---|---|
/foo/ |
忽略当前目录的foo 文件夹 |
/foo/* |
忽略当前目录的foo 文件夹下的所有文件(包括子文件夹) |
*.zip !main.zip |
忽略所有.zip 文件但不忽略 main.zip 文件 |
/foo/do.c |
忽略某个具体文件 |
!/foo/one.txt |
追踪(不忽略,即添加)某个具体文件 若还有规则 /foo/ ,则该规则不生效 |
/foo/* !/foo/one.txt |
忽略foo 文件夹中所有内容但不忽略 /foo/one.txt |
/* !/foo /foo/* !/foo/bar |
忽略所有内容,除/foo/bar 文件夹 |
高级规则
规则 | 作用 |
---|---|
bin/ |
忽略所有路径下的bin文件夹,该文件夹下的所有内容都会被忽略,不忽略 bin 文件 |
/bin |
忽略当前目录下的bin文件或bin文件夹 (bin文件和bin文件夹在同一级目录下只能存在一个) |
/bin/ |
忽略当前目录下的bin文件夹 |
/bin/* |
忽略当前目录的bin文件夹下的所有文件 (包括子文件夹) |
/*.c |
忽略当前目录下所有的c文件,不忽略 build/cat.c |
debug/*.obj |
忽略所有的 debug/io.obj 不忽略 debug/common/io.obj 和 tools/debug/io.obj |
**/foo |
忽略/foo , a/foo , a/b/foo 等 |
a/**/b |
忽略a/b , a/x/b , a/x/y/b 等 |
!/bin/run.sh |
不忽略 bin 目录下的 run.sh 文件若还有规则 /bin/ ,则该规则不生效 |
/foo/* !/foo/one.txt |
忽略foo 文件夹中所有内容但不忽略 /foo/one.txt |
/* !/foo /foo/* !/foo/bar |
忽略所有内容,除/foo/bar 文件夹 |
*.log !change.log |
忽略所有 .log 文件但不忽略 change.log 文件 |
config.php |
忽略当前路径及子路径的 config.php 文件 |
注意
需要注意的是,gitignore还可以指定要将哪些文件添加到版本管理中:唯一的区别就是规则开头多了一个感叹号,Git会将满足这类规则的文件添加到版本管理中。
为什么要有两种规则呢?假设我们只需要管理/mtk/
目录中的one.txt
文件,这个目录中的其他文件都不需要管理。那么我们就需要使用:
/mtk/*
!/mtk/one.txt
值得一提的是,以下写法是错误的,添加规则会失效:
/mtk/
!/mtk/one.txt
如果我们只有过滤规则没有添加规则,那么我们就需要把/mtk/
目录下除one.txt
以外的所有文件都写出来,而此时,添加规则极大的方便了我们的需求。
1.7. 解决换行符的替换问题
1.7.1. 问题
Windows平台下使用git add
时,经常会出现如下提示:
warning: LF will be replaced by CRLF in [filename].
The file will have its original line endings in your working directory
解释: Windows系统上,默认换行符为CRLF,但使用Vim编辑器进行编辑的文件,其换行符为LF。当LF的文件添加为缓存时,由于Git默认开启了core.autocrlf
,所以缓存文件中的LF(Unix的换行符)将被CRLF(Windows的换行符)替换;但本地工作区的LF不会被CRLF替换。
补充: 在Notepad和Notepad++的底部状态栏可以分辨某一文件的换行符是LF还是CRLF。
1.7.2. 分析
在文本处理中,CR(CarriageReturn),LF(LineFeed),是不同操作系统上使用的换行符,具体如下:
回车符(\r
):回到一行的开头,用符号r表示,十进制ASCII代码是13,十六进制代码为0x0D
,回车(return);
换行符(\n
):另起一行,用n符号表示,ASCII代码是10,十六制为0x0A
, 换行(newline)。
所以我们在Windows系统编写文件的回车符应该确切来说叫做回车换行符(CRLF)。
应用情况
Dos和Windows平台: 使用回车(CR)和换行(LF)两个字符来结束一行,回车+换行(CR+LF,即CRLF),即\r\n
;
Mac 和 Linux平台(类Unix系统):只使用换行(LF)一个字符来结束一行,即\n
;(早期Mac每行结尾是回车CR 即\r
,后来Mac os x 也投奔了 Unix。)
许多 Windows 上的编辑器会悄悄把行尾的换行(LF)字符转换成回车(CR)和换行(LF),或在用户按下 Enter 键时,插入回车(CR)和换行(LF)两个字符。
影响
一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;
而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。
Linux保存的文件在windows上用记事本看的话会出现黑点。
由于编辑器的不同或者文件行尾的换行符在 Windows 下被替换了,一些细微的空格变化会不经意地混入提交,造成麻烦。虽然这是小问题,但它会极大地扰乱跨平台协作。
这些问题都可以通过一定方式进行转换统一,例如,在Linux下,命令unix2dos
是把Unix文件格式(LF)转换成Windows文件格式(CRLF),命令dos2unix
是把Windows格式(CRLF)转换成Unix文件格式(LF)。
1.7.3. 解决方案
工作原理
以下为配置项core.autocrlf
的工作原理:
file to commit -> repository -> checked out file
core.autocrlf | file to commit | repository | checked out file |
---|---|---|---|
true | x | LF | CRLF |
input | x | LF | LF |
false | x | x | x |
注意: x可以是LF或CRLF,但上表中,每一行的x是不变的。
Windows系统
1. 方法一:
Git 的 Windows 客户端基本都会默认设置 core.autocrlf=true
,只要保持工作区都是纯 CRLF 文件,编辑器用 CRLF 换行,就不会出现警告了(注意:Git Bash命令行中Vim命令编辑的文件为LF格式文件)。
此时,提交时转换为LF,检出时转换为CRLF。
设置方法:
git config --global core.autocrlf true
注意:--global
为全局配置,若只想为某一项目配置,省略--global
即可。
2. 方法二:
设置 core.autocrlf=false
取消此功能,把回车保留在版本库中,即本地库和远程库都是CRLF格式。若开发只在Windows上运行的项目,则可以考虑此方法。
也可以在本地库和远程库都使用LF格式(通过Notepad++可以实现LF和CRLF格式的转换,下文有详细介绍),在Windows系统也用LF换行。除了旧版的记事本(新版好像也支持LF),其他编辑器都可以正常编辑。
设置方法:
提交检出均不转换
git config --global core.autocrlf false
你也可以在文件提交时进行safecrlf
检查:
拒绝提交包含混合换行符的文件
git config --global core.safecrlf true
允许提交包含混合换行符的文件
git config --global core.safecrlf false
提交包含混合换行符的文件时给出警告
git config --global core.safecrlf warn
注意:Windows 上设置 core.autocrlf=false
,仓库里也没有配置 .gitattributes
,很容易引入 CRLF 或者混合换行符(Mixed Line Endings,一个文件里既有 LF 又有CRLF)到版本库,这样就可能产生各种奇怪的问题。
Unix系统
包括Linux,Mac等类Unix系统
如果使用以换行(LF)作为行结束符的类Unix系统,你不需要 Git 在检出文件时进行自动的转换。
然而当一个以CRLF作为行结束符的文件不小心被引入时,你肯定想让 Git 修正。 可以把 core.autocrlf
设置成 input
来告诉 Git 在提交时把CRLF转换成LF,检出时不转换:(这样在 Windows 上的检出文件中会保留CRLF,而在Unix系统上,以及版本库中会保留LF。)
设置方法:
提交时转换为LF,检出时不转换
git config --global core.autocrlf input
**注意:**Unix 最好不要设置 core.autocrlf
,因为这个配置算是为 Windows 平台特殊定制的;
1.7.4. 配置 .gitattributes文件
该方案适用于各种系统(包括Windows和类Unix系统)
Git的.gitattributes
文件是一个文本文件,文件中的一行定义一个路径的若干属性。官方文档链接:gitattributes文档 。
格式
该文件以行为单位设置一个路径下所有文件的属性,格式如下:
要匹配的文件模式 属性1 属性2
模式匹配路径的规则与.gitignore
文件中的规则相同(详情请查看 1.5.3. 忽略规则配置语法 和 1.5.6. 忽略规则示例),少数例外情况除外:
- 禁止负型
- 匹配目录的模式不会递归匹配该目录中的路径,因此使用尾随斜杠
path/
语法在属性文件中毫无意义;应改为使用path/**
。
实例
* text=auto
# 文件的行尾自动转换。如果是文本文件,则在文件入Git库时,行尾自动转换为LF。如果已经在入Git库中的文件的行尾是GRLF,则文件在入Git库时,不再转换为LF。
*.txt text
# 对于.txt文件,标记为文本文件,并进行行尾规范化。
*.jpg -text
# 对于`.jpg`文件,标记为非文本文件
*.vcproj text eol=crlf
# 对于.vcproj文件,标记为文本文件,在文件入Git库时进行规范化,行尾转换为LF。在检测到出工作目录时,行尾自动转换为GRLF。
*.sh text eol=lf
# 对于sh文件,标记为文本文件,在文件入Git库时进行规范化,即行尾为LF。在检出到工作目录时,行尾也不会转换为CRLF(即保持LF)。
*.py eol=lf
# 对于py文件,只针对工作目录中的文件,行尾为LF。
属性
- text
控制行尾的规范性。如果一个文本文件是规范的,则Git库汇总该文件的行尾总是LF。对于工作目录,除了text
属性之外,还可以设置eol
属性或core.eol
配置变量。 - eol
设置行末字符。
eol=lf
,入库时将行尾规范为LF,检出时禁止将行尾转换为CRLF
eol=crlf
,入库时将行尾规范为LF,检出时将行尾转换为CRLF。 - diff
diff属性影响Git对特殊文件生成差异的方式。它可以告诉Git是否为路径生成文本补丁还是将路径视为二进制文件。它也可以影响在hunk
头部显示的@@ -k,l +n,m @@
,告诉Git使用外部命令来生成差异,或者是在生成差异之前让Git将二进制文件转换为文本文件。 - 其他属性即详情在这里不再介绍,请参照官方文档:gitattributes文档 。
优先级
- 同一个gitattributes文件中,按照行的先后顺序,优先级从上到下;如果一个文件的某个属性被多次设置,则后序的设置优先。
- 在一个Git库中可以有多个gitattributes文件,不同gitattributes文件中,属性设置的优先级如下(从高到低):
/myproj/.git/info/attributes # git仓库中的属性
/myproj/my_path/.gitattributes # 当前目录(对于my_path中的文件)
/myproj/.gitattributes # 父目录(对于my_path中的文件)
统一设置
也可以为所有Git库设置统一的gitattributes文件:
git config --get core.attributesFile
git config --global --get core.attributesFile
1.7.5. LF与CRLF格式相互转换
Windows系统
1. 查看文件换行格式
在Notepad和Notepad++的底部状态栏可以分辨某一文件的换行符是LF还是CRLF。
2. 相互转换
需要先安装Notepad++软件,使用该软件打开文件,点击编辑 -> 文档格式转换 -> 转换为[CRLF/LF/CR]
。
Linux系统
在Linux下,命令unix2dos
是把Unix文件格式(LF)转换成Windows文件格式(CRLF),命令dos2unix
是把Windows格式(CRLF)转换成Unix文件格式(LF)。
2. 远程库使用流程
使用Git大部分是多人协作的开发模式,所以一般远程库+本地库共同使用,先讲述一下远程库的使用流程,而远程库的流程自然包括本地库的使用流程。后面会单独介绍本地库的使用流程。
远程库使用流程包括新建远程仓库,配置开发者用户信息,设置SSH key,设置多个SSH key(可不设),检测是否成功配置SSH key,局域网内搭建Git远程仓库,将远程库克隆到本地,创建和切换分支,下拉代码,上传代码,合并分支,合并冲突,减少冲突,撤销更改,版本回退,整理提交历史,使用rebase合并分支,等等。具体流程如下:
2.1. 基本流程
基本流程指正常完成某一操作的最基本的流程。扩展流程指在某个特定条件下要执行的流程。
2.1.1. 新建远程仓库
-
方式一(推荐): 借助网络平台建立远程仓库
通过Web端(如GitHub,DevCloud等)新建仓库与分支,方法请自行查询或探索。在网页端可以复制SSH地址或HTTPS地址。后续会使用该地址与远程库进行连接,详情见2.1.7. 连接远程仓库。 -
方式二: 局域网内搭建Git远程仓库
Windows环境下,在局域网开发有时不能连接到GitHub,因此需要建立一个公共的远程库供项目组使用。详情请见2.2.2. 局域网内搭建Git远程仓库。
2.1.2. 配置开发者的全局用户信息
git config --global user.name "username"
git config --global user.email "[email protected]"
以上为git全局的用户名和邮箱,不加--global
即配置当前仓库的信息,只有配置好用户名和邮箱后才可以使用接下来的功能。
查看配置好的配置信息:
git config --list
查看配置好的全局配置信息:
git config --global --list
2.1.3. 连接远程仓库的方式
HTTPS方式:适合初学者,操作简单,但使用较麻烦。
SSH方式(推荐):适合对电脑有一定基础的用户,配置较麻烦,但使用方便。
区别:使用https url克隆对初学者来说会比较方便,复制https url然后到git Bash里面直接用clone命令克隆到本地就好,但是每次pull
和push
代码都需要输入账号和密码,这也是https方式的麻烦之处。而使用SSH url克隆却需要在克隆之前先配置和添加好SSH key,配置好后,使用方便。
注意:若使用HTTPS方式,则可直接跳到2.1.7. 连接远程仓库,若使用SSH方式,则需要继续看2.1.4. 设置SSH key。
2.1.4. 设置SSH key(默认只设1个)
-
检查你电脑是否已经有 SSH key
cd ~/.ssh // 跳转到ssh文件夹 ls // 列出文件夹中的文件
若
.ssh
文件夹不存在,则继续第2步创建SSH密钥;若存在 id_rsa.pub 或 id_dsa.pub 文件,则已存在SSH密钥,可以直接跳到第3步,或到第2步重置SSH密钥。 -
创建SSH密钥
ssh-keygen -t rsa -C "yourEmail"
或
ssh-keygen -t rsa -C "yourEmail" -f ~/.ssh/[rsafilename]
-t
后接密钥类型,默认为rsa
,可省略;
-C
设置注释文字,比如邮箱。
-f
指定密钥文件存储文件名,可省略,省略后会在当前文件夹创建。
[rsafilename]
为rsa私钥文件的名称。输入第1条命令后会提示输入文件名和密码,按3个回车即可,也可自定义文件名和密码;如果输入第2条命令,则直接提示输入密码,按2个回车或自定义密码即可。
-
复制SSH公钥
clip < ~/.ssh/id_rsa.pub
或
cat ~/.ssh/id_rsa.pub
-
将SSH公钥粘贴到 GitHub 对应的位置(以下2种)并点击确定。
GitHub账户最高权限SSH(推荐):
右上角头像 ->Settings
->SSH and GPG keys
->New SSH key
;仓库SSH:
进入远程仓库 ->Settings
->Deploy keys
->Add deploy key
。二者区别:
GitHub账户的SSH keys
,相当于这个账号的最高级key,只要是这个账号有的权限(任何项目,包含协作项目),都能进行操作。仓库的
Deploy keys
,顾名思义就是这个仓库的专有key,用这个key,只能操作这个项目,其他项目都没有权限。注意: 由于1个SSH key只能配置在1个GitHub账户或仓库上,因此推荐将SSH key配置在账户的最高权限上。
2.1.5. 设置多个SSH key(可省略)
可只用默认的1个SSH key,不设多个,但当同时需要2个SSH的时候需要设置。因为GitHub的某一个SSH只允许一个账户或仓库使用,所以一个终端经常需要设置多个SSH。步骤如下:
-
创建另一个密钥
方法一:ssh-keygen -t rsa -C "yourEmail" -f ~/.ssh/test_rsa
-f
直接指定文件路径及名称;之后的密码可以都是回车。方法二:
ssh-keygen -t rsa -C "yourEmail"
不要一路回车,让你选择在哪里选择存放SSH key的时候写个名字,比如
github_rsa
,之后的密码可以回车。 -
添加SSH密钥代理(临时)
该方式是临时性的,重启ssh-agent服务后需要重新输入;若要永久保存设置(推荐),则需要配置config
文件,详情见下一步,配置config文件,若配置了config
文件,则无需再添加SSH密钥代理。添加SSH密钥代理步骤如下。
打开ssh-agent:
若为Windows系统,则命令为ssh-agent bash
若其他系统,命令为ssh-agent -s
或eval $(ssh-agent -s)
添加私钥:
ssh-add ~/.ssh/test_rsa
-
配置config文件(推荐)
配置私钥对应的服务器,可永久保存配置,步骤如下。
创建文件:touch ~/.ssh/config
修改文件:vim ~/.ssh/config
插入:按字母“I
”,输入如下信息# GitHub Host github.com HostName github.com Preferredauthentications publickey IdentityFile ~/.ssh/github_rsa User NSJim # TestRepository Host test HostName github.com Preferredauthentications publickey IdentityFile ~/.ssh/test_rsa User NSJim
保存文件:按
Esc
,然后输入":wq
"。或者使用记事本修改,文件位置如下:
C:\Users\[username]\.ssh\config
变量说明:
Host
:可随意填写,方便自己记忆,是替换HostName
的变量,后续在添加remote(远程库)时还需要用到;
HostName
:远程库SSH地址的“git@
”与“:
”之间的域名(网站的或公司的,如GitHub的HostName
为github.com
);
IdentityFile
:填写对应的私钥文件及路径;
User
:用户名,可有可无,起标识作用。
配置完成后,在连接非默认帐号的github仓库时,远程库SSH地址要对应地做一些修改,把HostName
替换为Host
。例如:git remote add orgin [email protected]:NSJim/test.git
要改为:
git remote add orgin git@test:NSJim/test.git
git clone [email protected]:NSJim/test.git
要改为:
git clone git@test:NSJim/test.git
-
复制SSH公钥
clip < ~/.ssh/id_rsa.pub
或
cat ~/.ssh/id_rsa.pub
-
将SSH公钥粘贴到GitHub对应的位置(2种,步骤3-4已提及)并点击确定
2.1.6. 检测是否成功配置SSH key
-
默认SSH key检测:
ssh -T [email protected]
然后输入
yes
回车,若提示Hi, username!
则成功。 -
非默认SSH key检测(设有多个SSH key时):
ssh -T git@[Host]
Host
为~/.ssh/config
中的Host
,用来代替HostName
;若提示Hi, username!
则成功。
2.1.7. 连接远程仓库
即本地库与远程库的连接,为后续进行代码的pull
和push
做准备。需要使用2.1.1. 新建远程仓库中的SSH地址或HTTPS地址。
-
方式一(推荐):将远程仓库clone到本地
git clone [url]
[url]
即远程库的SSH url
或HTTPS url
(地址),需从网页端的远程仓库复制。 -
方式二:本地仓库初始化并连接
该方式先进行本地仓库的初始化,然后再进行远程库连接,该方法略微麻烦,效果和方式一相同。优点是可以自定义本地仓库文件夹的名称,并可将仓库文件夹中的代码
push
到远程库中。(1) 移动到要初始化为仓库的文件目录中:
cd [path]
(2) 本地仓库初始化(即将当前目录设置为git仓库):git init
(3) 添加远程仓库,命令如下:git remote add [remotename] [url]
[remotename]
为自定义的远程库的名字,默认为origin
;[url]
为远程仓库的SSH地址或HTTPS地址。(4) 设置上流分支
git branch -u [remotename]/[remotebranchname] [localbranchname]
或
-u
的全称--set-upstream-to
:git branch --set-upstream-to [remotename]/[remotebranchname] [localbranchname]
同
git branch --set-upstream-to=[remotename]/[remotebranchname] [localbranchname]
设置
[remotename]
远程库的[remotebranchname]
分支作为本地当前分支[localbranchname]
的上游分支,一般情况下,[remotebranchname]
和[localbranchname]
相同。若要执行
push
操作,也可执行命令:git push --set-upstream [remotename] [localbranchname]
将本地分支
[localbranchname]
推送到[remotename]
远程库的[localbranchname]
分支。(5) 示例:
cd /d/Work/Project git init git remote add origin [email protected]:WongJay/w3cschool.cn.git git branch --set-upstream-to origin/master master
2.1.8. 配置开发者的仓库用户信息
git config user.name "username"
git config user.email "[email protected]"
以上为配置git仓库的用户名和邮箱,在与远程仓库交互时,会覆盖已配置的全局用户信息。若已经配置了全局的用户信息,也可不必配置仓库的用户信息,默认会调用全局用户信息。
2.1.9. 分支操作
- 移动到本地git仓库:
cd [gitPath]
- 查看已有分支:
git branch
带*
和高亮的为当前分支 - 创建分支:
git branch [branchname]
- 切换分支:
git checkout [branchname]
切换前需先进行提交(commit)。 - 创建并切换分支:
git checkout -b [branchname]
- 删除分支:
git branch -d [branchname]
若没有合并分支,则不能删除。 - 强制删除分支:
git branch -D [branchname]
2.1.10. 下拉代码(重要)
git pull
即从服务器下载当前分支的最新版本到本地(只会下载有更新的文件,一般不会覆盖本地已修改的文件)。在开始工作时(进行更改前),上传代码前,合并分支前,都需要先进行git pull
。
若提示: 请指定要合并的分支,如下:
Please specify which branch you want to merge with.
解决方案:
有2个方案,在下方详细介绍。若是通过git init
新建的空仓库出现该提示,则需要先使用方案二(指定远程分支),之后在进行方案一(设置上游分支);其他情况直接使用方案一即可。
方案一(推荐): 设置上游分支
git branch -u [remotename]/[remotebranchname] [localbranchname]
或
git branch --set-upstream-to=[remotename]/[remotebranchname] [localbranchname]
[remotename]
为远程库名称,[remotebranchname]
为远程库分支,[localbranchname]
为本地分支,一般情况下,[remotebranchname]
和[localbranchname]
相同。
方案二: 指定远程分支
git pull [remotename] [branchname]
[remotename]
和[branchname]
的含义同上。
2.1.11. 上传代码
-
git status
查看项目当前的文件更新状态,也可以用git status -s
简洁显示,一般与git diff
命令配合使用,可省略。在任何时刻都可使用git status
或git status -s
命令查看状态。git status -s的几种状态:
A (added)
:你本地新增的文件(服务器上没有)。
C (copied)
:文件的一个新拷贝。
D (deleted)
:你本地删除的文件(服务器上还在)。
M (modified)
:文件的内容或者mode被修改了,红色为修改过未被添加进暂存区的,绿色为已经添加进暂存区的。
R (renamed)
:文件名被修改了。
T (typed)
:文件的类型被修改了。
U (updated but unmerged)
:文件没有被合并(你需要完成合并才能进行提交)。
?
:未被git进行管理,可以使用git add file1把file1添加进git。
X
:未知状态(很可能是遇到了git的bug) -
git add .
将所有文件添加到缓存,也可使用git add [file1] [file2]
单独添加文件。注意:被
add
的文件便可被git管理,没有被add
的文件不会被git管理。 -
git status -s
再次查看项目当前的文件更新状态,可省略。 -
git commit -m "[message]"
将缓存提交到本地仓库,[message]
为备注信息。若觉得每次都add
后才能commit
比较麻烦,可以使用git commit -am "[message]"
来跳过add
,但新文件和重命名文件不会被commit
。注意:要提前配好git仓库的用户名和邮箱才能正常使用该命令。
-
git push
将本地库推送(即上传)到远程库提示没有上游分支
报错如下:
fatal: The current branch a has no upstream branch.
方案一(推荐): 设置上游分支
git push -u [remotename] [branchname]
或
git push --set-upstream [remotename] [branchname]
-u
为简写,--set-upstream
为全称。[remotename]
为远程库的别名,在6.1.1. 添加远程仓库中有详细解释。
将远程库[remotename]
的远程分支[branchname]
作为其上游分支;方案二: 指定远程分支
git push [remotename] [branchname]
[remotename]
的含义同上。
指定推送到[remotename]
远程库的[branchname]
分支,但该方法下次还会出现fatal
提示。强制推送
git push --force 或 git push -f
2.1.12. 合并分支
- 方法一:
网页上新建分支请求、接受合并请求。 - 方法二:
命令行合并,步骤如下:
(1) 切换到主分支
(2) 下拉刷新:git pull
(3) 合并分支:git merge [branchname]
branchname
是要合并的分支名称,也可以在末尾添加-m "[message]"
参数。
(4)上传合并分支:git push
2.2. 扩展流程
2.2.1. 设置多个SSH key
由于该步骤比较常见,所以分类归到了基本流程当中,详情请查看2.1. 基本流程中的2.1.5. 设置多个SSH key。
可只用默认的1个SSH key,不设多个,但当同时需要2个SSH的时候需要设置。因为GitHub的某一个SSH只允许一个账户或仓库使用,所以一个终端经常需要设置多个SSH。
2.2.2. 局域网内搭建Git远程仓库
使用局域网开发有时不能连接到GitHub,因此需要建立一个公共的远程库供项目组使用。在Windows10系统环境下,步骤如下。
-
在公共服务器下创建远程仓库
公共服务器(局域网服务器)可以是局域网中任意一台电脑,当做Git的远程仓库来使用,创建的远程仓库为空仓库。可供其他电脑进行代码的pull
和push
。步骤如下。(1) 创建一个文件夹,如
public.git
mkdir public.git
(2) 进入该文件夹,建立裸仓库
git init --bare
-
设置网络访问权限
(1) 设置共享文件夹及共享权限
设置public.git
为共享文件夹。右键文件夹 —> 属性 —> 共享 —> 高级共享;设置共享名,添加;设置权限,编辑组和用户名,默认为Everyone
,为Everyone
添加允许完全控制权限。(2) 检测文件夹是否可访问
确认在本机文件管理器中通过共享文件夹路径\\IP地址\共享文件夹名称
或\\主机名称\共享文件夹名称
访问到,推荐使用IP地址,因为主机名可能出现重名冲突,而且速度更快,更精确。IP地址
为本机(公共服务器)的IP地址,可通过Win10的 CMD命令提示符 的ipconfig
命令查看,对应的网络适配器的IPv4
地址即为本机的 IP地址。主机名称
可以右键桌面的 此电脑 图标,点击属性可以查看。也可在Git bash
命令行中查看,@
前面的即为主机名。注意: 共享文件夹名称可以与文件夹名称不同;共享文件夹路径的主机名称和共享文件夹名称不规范大小写;Git访问时,应该使用正斜杠
/
。 -
项目组成员连接局域网远程仓库
项目组成员在自己的机器(包括公共服务器本机)上,参照以下2种方法连接远程库,大家就可以通过Git一起工作了。 其他操作请参照 2. 远程库使用流程 。注意:连接前要保证项目组都在同一局域网中,即项目组的机器与局域网公共服务器之间在 CMD命令提示符 中可以
ping
通,命令为ping IP地址
;若无法ping通,则各机器不在同一局域网中,可通过 2.1.1. 新建远程仓库 中的 方式一:借助网络平台建立远程仓库 来搭建远程远程仓库。方法一:添加远程库
(1)git remote add [remotename] [sharepath]
[remotename]
可以自定义,是远程库的别名,默认为origin
[sharepath]
为共享文件夹路径,一般为//IP地址/共享文件夹名称
或//主机名称/共享文件夹名称
,推荐使用IP地址,因为主机名可能出现重名冲突,而且速度更快,更精确。
使用git remote -v
命令查看一下设置远程库是否成功。(2) 进入本地库,将本地代码
push
到远程库
git push -u [remotename] master
-u
可以替换为全称--set-upstream
。[remotename]
的含义同上,但要注意2个命令中的[remotename]
要保持相同。该命令可同时设置好上游分支。方法二:克隆远程库
通过克隆的方式将空的远程库克隆到本地,然后将项目文件拷贝到本地库,之后再将本地库push
到远程库。
git clone [sharepath]
[sharepath]
为共享文件夹路径,一般为//IP地址/共享文件夹名称
或//主机名称/共享文件夹名称
。推荐使用IP地址。 -
注意事项
(1) 密码保护
若共享设置中开启了密码保护,则项目组用户必须拥有公共服务器的用户账户(主机名)和密码(登录密码),才能访问共享文件夹。项目组成员在进行pull
和push
时需要填写用户账户和密码才能继续操作。在
控制面板\网络和 Internet\网络和共享中心\高级共享设置\所有网络\密码保护的共享
处,可以设置无密码保护的共享。(2) 共享权限设置
共享文件夹的权限一定要设置好,方法请见上文的设置网络访问权限中的设置共享权限,否则项目组的其他用户没有写权限,则无法进行push
,会报如下错误。error: remote unpack failed: unable to create temporary object directory ! [remote rejected] master -> master (unpacker error) error: failed to push some refs
(3) 网络发现
若想更直观的看到网络中共享的文件夹,则可以开启网络发现功能,这样则可在文件资源管理器的网络中看到共享的主机。开启方法:控制面板\网络和 Internet\网络和共享中心\高级共享设置\相应的网络\
中,启用网络发现
,启用文件和打印机共享
。若文件资源管理器中的网络没有其他计算机,则需要检查Windows功能
Smb1.0
是否开启,开启方法:打开控制面板——程序与功能——启用或关闭windows功能——smb1.0/cifs 文件共享支持
,打上勾,并重启。
2.2.3. 删除分支
git branch -d [branchname]
普通删除,若没有合并分支,则不能删除。git branch -D [branchname]
强制删除分支。
2.2.4. 输入提交信息
当git commit
时,若忘记填写-m
参数,命令行会提示
Please enter the commit message for your changes.
此时需要在vim编辑器中按 I
键填写message
,然后按Esc
键,输入:wq
,保存退出。
2.2.5. 输入合并信息
当git pull
或git merge
时,命令行可能会提示:
Please enter a commit message to explain why this merge is necessary.
此时,可以按 I
键编辑message
,也可以直接按Esc
键,输入:wq
,保存退出。
注意:git merge
可以有-m
参数,即:
git merge [branchname] -m "[message]"
2.2.6. 修改已提交造成合并冲突
当2人同时修改同一文件,并均已提交推送至不同的分支,进行分支合并时,会出现冲突。
需手动合并,打开冲突文件,显示格式如下:
<<<<<<< HEAD
123 789
456 123
789 456
=======
123 123
456 456
789 789
>>>>>>> [branchname]
HEAD
指当前所在分支,branchname
指要合并的分支名。
<<<<<<< HEAD
和 =======
之间为当前所在分支内容;=======
和 >>>>>>> [branchname]
之间为要合并的分支内容。
手动合并(即修改)结束后,要重新上传代码:
提交到缓存:git add .
提交到本地库:git commit -m “message”
推送到远程库:git push
合并冲突结束。
2.2.7. 本地修改未提交造成合并冲突
在使用git pull
或git merge
时,可能会出现如下错误:
error: Your local changes to the following files would be overwritten by merge:
[files]
Please, commit your changes or stash them before you can merge.
这种情况大多是由于修改了文件,然后没有及时提交到本地库或远程仓库中造成的冲突,工作中经常发生这种冲突。
解决方案有3种:
方案一(推荐):Stash方法
git stash
git pull
git stash pop
进行pop
操作后,可能会出现冲突,进行上一步骤的合并冲突操作即可。
说明:
git stash
:备份当前的工作区的内容,从最近的一次提交中读取相关内容,让工作区保证和上次提交的内容一致。同时,将当前的工作区内容保存到Git栈中。
git stash pop
:从Git栈中读取最近一次保存的内容,恢复工作区的相关内容。由于可能存在多个Stash的内容,所以用栈来管理,pop会从最近的一个stash中读取内容并恢复。
git stash list
:显示Git栈内的所有备份,可以利用这个列表来决定从那个地方恢复。
git stash clear
:清空Git栈。此时使用gitg等图形化工具会发现,原来stash的哪些节点都消失了。
方案二:放弃修改,直接覆盖
git reset --hard
git pull
方案三:手动备份
先备份好本地写好的代码,然后放弃本地修改,然后进行pull
或merge
,然后再把要修改的文件直接覆盖掉,然后再进行提交。
2.2.8. 撤销更改
(1) 场景1:
当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时使用该命令:git checkout -- [file]
。
(2) 场景2:
当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改。分两步:第一步用命令git reset HEAD [file]
,就回到了场景1,第二步按场景1操作。
(3) 场景3:
已经提交了不合适的修改到版本库时,想要撤销本次提交,参考下一步骤,版本回退,不过前提是没有推送到远程库。
场景2示例:
所有文件取消添加缓存:git reset HEAD .
所有文件丢弃工作区修改:git checkout -- .
要注意命令后方有 .
,代表所有文件,也可单独列出某一文件。
2.2.9. 版本回退
Git允许我们在版本的历史之间穿梭,命令:
git reset --hard commit_id
。
要回到过去,用git log
可以查看提交历史和commit_id
,以便确定回退版本。若要在log
界面上下翻页,则按上下箭头(或回车)即可;要退出log
界面,按字母键Q
即可。
要重返未来,用git reflog
查看命令历史,以便确定要回到未来的哪个版本,再用git reset
命令重置为指定版本。
版本回退后,要强制推送到远程库才会起作用,否则只是本地库的版本回退,命令为 git push --force
或 git push -f
。
关于commit_id(版本号):
当前版本为HEAD
,上一个版本就是HEAD^
或HEAD~1
,上上一个版本就是HEAD^^
或HEAD~2
,当然往上100个版本写100个^
并不容易,所以可以写成HEAD~100
。
可以使用HEAD
或commit_id
进行版本回退。若记不清是上几个版本,可以使用git log
可以查看提交历史及对应的commit_id
,以便确定要回退到哪个版本。
版本号(commit_id
)没必要写全,前几位就可以了(一般四位就够了),Git会自动去找。当然也不能只写前一两位,因为Git可能会找到多个版本号,就无法确定是哪一个了。
示例:
返回当前版本(即撤销更改):git reset --hard
或git reset --hard HEAD
返回上一版本:git reset --hard HEAD^
返回特定版本:git reset --hard [commit_id]
强制推送:git push --force
其他
相似的,也可尝试 git revert
命令。
3. 本地库使用流程
Git也可仅适用本地库进行版本管理,不与远程库进行连接。本地库的版本管理不需要使用SSH key进行验证,也不需要进行clone,pull和push,即把远程库流程中的SSH key操作,clone,pull和push操作去掉即可变为本地库的流程。本地库使用流程如下:
3.1. 基本流程
-
本地仓库初始化(将当前目录设置为git仓库):
git init
-
配置开发者的用户信息:
git config --global user.name "username" git config --global user.email "[email protected]"
以上为git全局的用户名和邮箱,不加
--global
即配置当前仓库的信息 -
创建和切换分支(初始化后默认为master分支):
(1) 查看已有分支():git branch
带*
和高亮的为当前分支
(2) 创建分支:git branch [branchname]
(3) 切换分支:git checkout [branchname]
切换前需先进行提交(commit)。
(4) 创建并切换分支:git checkout -b [branchname]
-
上传代码到本地库:
(1)git status
查看项目当前状态,也可以用git status -s
简洁显示,一般与git diff
命令配合使用,也可不查看状态直接进行git add
。可在任何时刻使用git status
或git status -s
命令查看状态。(2)
git add .
将所有文件添加到缓存,也可使用git add [file1] [file2]
单独添加文件。
注意:被add
的文件便可被git管理,没有被add
的文件不会被git管理。(3)
git commit -m "message"
将缓存提交到本地仓库,message
为备注信息。若觉得每次都add
后才能commit
比较麻烦,可以使用git commit -am "message"
来跳过add
,但新文件和重命名文件不会被commit
。
注意:要提前配好git仓库的用户名和邮箱才能正常使用该命令。 -
合并分支:
(1) 切换到主分支
(2) 合并分支:git merge [branchname]
branchname
是要合并的分支名称 -
合并冲突
在远程库的使用流程中也涉及,此处不再重复。
3.2. 扩展流程
扩展流程同远程库的扩展流程,这里不再赘述,内容如下:
- 删除分支
- 合并冲突
- 撤销更改
- 版本回退
4. IDE集成Git使用流程
4.1 介绍
目前很多的IDE(Integrated Development Environment,集成开发环境)都已经集成了Git,如JetBrains IDEA,Visual Studio,微信开发者工具,等等。用户不需要想以前一样只能使用命令行进行代码的版本控制与合作,而是可以在IDE的图形化界面中操作。
当然,即使IDE集成了Git,我们也可以使用Git Bash命令行进行操作,二者互不影响,可以同时使用。下面我以JetBrains的IDEA为例,进行一些基础的讲解,其他软件的操作方法类似。更深入的操作和使用方法可以自行探索。
4.2 IDE与Git连接
- 下载安装Git Bash,下载地址:下载链接 。
- 打开Git Bash命令行,配置开发者的全局用户信息
以上为git全局的用户名和邮箱,不加git config --global user.name "username" git config --global user.email "[email protected]"
--global
即配置当前仓库的信息。 - 打开IDEA软件,
File/Configure -> Settings -> Version Control -> Git
,在Path to Git executable中选择上一步Git Bash安装目录中的cmd文件夹下的git.exe
文件。点击右侧的Test,会弹出Git Executed Successfully
提示框。如下图:
- 在
File -> Setting -> Version Control -> GibHub
中,Host
填写github.com
,点击Create API Token
,输入在GitHub中注册的用户名和密码,然后会自动生成Token
。点击Test,测试是否连接成功。如下图。
4.3. 集成Git使用流程(图形化操作)
使用时与远程仓库的使用流程大同小异,只是把命令行操作换成了图形化界面而已。其使用流程也分为2个方式,建立本地库和克隆远程库2种。
4.3.1. 工作目录的状态
IDEA软件的工作目录中:
红色代表未被Git管理;
绿色代表以添加到缓存;
白色代表已提交至本地库;
蓝色代表已修改。
4.3.2. 建立本地库方式
- 创建本地库
打开IDEA软件,VCS -> Import into Version Control -> Create Git Repository
,然后选择相应的项目目录。之后工作目录的文件会变红。 - 添加远程库
VCS -> Git -> Remote
,或右键项目Git -> Repository -> Remote
,点击右侧的加号,填写Name
和URL
,Name
默认为Origin
,URL
为远程仓库地址,可以是HTTPS
或SSH
方式。 - 添加到缓存
右键项目Git -> add
,或快捷键Ctrl+Alt+A
,将文件添加到Git缓存。 - 提交及推送
右键项目Git -> Commit Directory
,或快捷键Ctrl+K
,或点击软件右上方的Commit按钮;输入Commit Message
,若想节省时间,可以取消勾选Porform code analysis
和Check TODO
。
之后点击弹窗下方的Commit
,或下拉箭头中的Commit and Push (Ctrl+Alt+K)
,即可完成提交或推送。如下图:
- 从远程库拉取代码
右键项目Git -> Repository -> Pull
,选择相应的Remote
,Branch
,Strategy
,之后点击Pull
即可。
或者直接点击软件右上方的Update Project (Ctrl+T)
,选择相应的Update Type
,点击OK
即可。 - 分支操作
在软件右下角的Git:
后面会显示当前分支,点击此处,可以显示所有分支并进行切换(checkout
即为切换),也可进行创建新分支,删除分支等操作。如下图:
- 合并
右键项目Git -> Repository -> Merge Changes
。 - 处理冲突
可以选择接受哪个更改,也可以先合并,然后再手动更改,更改之后要进行add
,commit
和push
。 - 栈操作
入栈:右键项目Git -> Repository -> Stash Changes
。
出栈:右键项目Git -> Repository -> Unstash Changes
。 - 查看提交历史
右键项目Git -> Show History
,即可查看提交历史。 - 版本回退
右键项目Git -> Repository -> Reset HEAD
,在To commit
中填写HEAD^
或HEAD~1
进行版本回退,点击Validate
按钮可以查看回退的版本信息。
注意: 当前版本为HEAD
,上一个版本就是HEAD^
或HEAD~1
,上上一个版本就是HEAD^^
或HEAD~2
,当然往上100个版本写100个^
并不容易,所以可以写成HEAD~100
。
4.3.3. 克隆远程库方式
-
从远程库克隆代码
在IDEA的Welcome界面,选择Check out from Version Control -> Git
,然后填写URL
和Directory
,URL
为远程库地址,可以是HTTPS
或SSH
方式。Directory
为项目路径,必须是空文件夹。点击Clone
即可克隆代码。在IDEA的项目界面下,
VCS -> Git -> Clone
或右键项目Git -> Repository -> Clone
,可同样进入Clone
界面。 -
其他操作
其他操作与上一方式(建立本地库方式)相同。
5. Git GUI使用流程
由于Git GUI的使用流程的原理与Git Bash相同,且操作方式与IDE集成的Git极其相似,因而在此不进行详细介绍,感兴趣的可以查看另一个博主的一篇博客:Git GUI的使用 。
打开Git GUI的方法:
在文件资源管理器中右键,点击Git GUI here
即可。
6. 常用命令
6.1. 远程仓库命令
6.1.1. 添加远程库
若使用SSH方式则需要先配置SSH key;若使用HTTPS方式则需要在后续使用时输入HTTPS凭据的账户和密码。以下为添加远程库命令。
git remote add [remotename] [url]
[remotename]
为自定义的远程库别名,默认为origin
;
[url]
为远程仓库的SSH地址或HTTPS地址。
示例:
git remote add origin [email protected]:WongJay/w3cschool.cn.git
6.1.2. 查看当前的远程仓库
git remote
git remote -v
执行时加上 -v 参数,你还可以看到每个别名的实际链接地址。
6.1.3. 提取远程仓库
- 从远程仓库下载新分支与数据:
该命令执行完后需要执行git fetch [remotename] [branch] git merge [remotename] [branch]
git merge
远程分支到你所在的分支。在已经设置上流分支的情况下可省略[remotename]
和[branch]
。 - 从远端仓库提取数据并尝试合并到当前分支(推荐):
该命令就是在执行git pull [remotename] [branch]
git fetch
之后紧接着执行git merge
远程分支到你所在的任意分支。在已经设置上流分支的情况下可省略[remotename]
和[branch]
。
6.1.4. 推送到远程仓库
git push [remotename] [branch]
以上命令将你的 [branch]
分支推送成为 [remotename]
远程仓库上的 [branch]
分支。在已经设置上流分支的情况下可省略 [remotename]
和 [branch]
。
注意:同一分支才可push
,不同分支需要merge
,实例如下。
git push origin master
6.1.5. 删除远程仓库
git remote rm [remotename]
6.2. 其他命令
6.2.1. 查看用户配置信息
- 查看所有
git config -l
- 查看特殊
git config user.name
6.2.2. 状态
- 查看状态
git status
- 简要查看状态
git status -s
- 几种状态如下:
A (added)
:你本地新增的文件(服务器上没有)。
C (copied)
:文件的一个新拷贝。
D (deleted)
:你本地删除的文件(服务器上还在)。
M (modified)
:文件的内容或者mode被修改了,红色为修改过未被添加进暂存区的,绿色为已经添加进暂存区的。
R (renamed)
:文件名被修改了。
T (typed)
:文件的类型被修改了。
U (updated but unmerged)
:文件没有被合并(你需要完成合并才能进行提交)。
?
:未被git进行管理,可以使用git add file1把file1添加进git。
X
:未知状态(很可能是遇到了git的bug)
6.2.3. 显示改动
git diff
执行 git diff
来查看执行 git status
的结果的详细信息。
git diff
命令显示已写入缓存与已修改但尚未写入缓存的改动的区别。
- 尚未缓存的改动:
git diff
- 查看已缓存的改动:
git diff --cached
- 查看已缓存的与未缓存的所有改动:
git diff HEAD
- 显示摘要而非整个 diff:
git diff --stat
6.2.4. 分支
- 普通删除分支
git branch -d [branchname]
- 强制删除分支
git branch -D [branchname]
6.2.5. 缓存
- 将单个或多个文件上传到缓存
git add [filename] [filename2]
filename
为文件的路径及名称,可使用相对路径,文件夹符号使用“/
”。 - 丢弃工作区的修改
git checkout -- [filename]
- 取消缓存已缓存的内容
git reset HEAD [filename]
- 将文件从缓存区中移除
git rm [filename]
默认情况下,git rm file
会将文件从缓存区和你的硬盘中(工作目录)删除。 如果要在工作目录中留着该文件,可以使用命令:git rm --cached [filename]
。 - 将文件夹从缓存区中移除
git rm -r [dirname]
6.2.6. 提交日志(log)
- 查看提交历史
git log
- 查看未来的提交历史
git relog
6.2.7. 重定基底(rebase)
- 合并提交(commit)
(1) 将提交历史整理成一条直线
git rebase
(2) 合并最近4条合并记录
git rebase -i HEAD~4
- 合并分支(在work分支下)
git rebase master
6.2.8. Git栈(stash)
git stash
:备份当前的工作区的内容,从最近的一次提交中读取相关内容,让工作区保证和上次提交的内容一致。同时,将当前的工作区内容保存到Git栈中。git stash pop
:从Git栈中读取最近一次保存的内容,恢复工作区的相关内容。由于可能存在多个Stash的内容,所以用栈来管理,pop会从最近的一个stash中读取内容并恢复。git stash list
:显示Git栈内的所有备份,可以利用这个列表来决定从那个地方恢复。git stash clear
:清空Git栈。此时使用gitg等图形化工具会发现,原来stash的哪些节点都消失了。