Git使用流程及技巧 - 详细教程

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. 基础技巧

  1. 打开Git命令行:Git Bash的快捷方式或在文件资源管理器中右键Git Bash Here。
  2. 命令行中的基础操作同Linux命令行,如创建文件夹,Vim命令等。关于Linux的命令行基础命令和用法,详情请参见W3CSchool的教程网站:Linux教程
  3. 命令行中的 ~ 指根目录,即C:\Users\[username]\
  4. 在命令行中进行的全局设置(git config --global)保存在根目录下的.gitconfig文件中,可以使用笔记本进行查看和更改;进行的项目设置(git config)保存在项目文件夹下的.git/config文件中。
  5. 命令行中的文件目录使用符号 / ,例如:D:\Work\Temp 在命令行中要写成 d/work/temp 。路径名和文件名不区分大小写,且可以用Tab进行补全。
  6. 命令行中,单引号可以代替双引号,但一定要左右匹配,且为英文标点符号。
  7. 命令行中,若忘记命令的使用方法或options,则可以添加-h参数,查看帮助,如:git remote -h
  8. Git连接远程库有2种方式:HTTPS和SSH(推荐),正文有详细介绍。
  9. 在整个项目中,项目的文件夹名称,文件名称,Commit Message,Merge Message,等等,尽量不要使用中文。全部用英文较好,否则可能会出现命令行乱码问题。(乱码问题对功能没有影响,但可能会影响项目成员对文件和提交历史的识别)
  10. 当GitHub仓库的上传文件接口不起作用时,可能是浏览器的兼容问题,可以试试谷歌或火狐浏览器。
  11. 在GitHub平台的项目仓库中,文件夹名称中可能会出现斜杠符号 / ,众所周知,文件夹名称中不可能包含符号 / ,所以该符号表示该文件夹包含的子文件夹。
    举一个例子:名称为page/images的文件夹,代表page文件夹下的images文件夹。
  12. 本篇文章中,所有的[filename]都可以用 . 代替,代表当前目录所有文件。

1.2. 提升SSH传输速度

在使用 SSH 方式在GitHub上进行代码托管时,一般速度会很慢,可以修改Git软件的配置,即关闭GSS API校验来提升速度,解决方案如下。

解决方案
以Windows 10系统为例:

  1. 找到Git软件的安装目录,例如:D:\Program Files\Git
  2. 进入etc\ssh目录,找到ssh_config文件,使用Notepad打开。
  3. GSSAPIAuthentication no前面的注释#删掉,或新增一行GSSAPIAuthentication no,保存文件。
  4. 再次使用ssh命令操作GitHub项目,可以体验到速度的提升,本人从100k/s变为5M/s,速度提升50倍。

若无法找到Git软件安装目录,可以右键快捷方式,选择打开文件位置

也可以使用vim命令编辑ssh_config文件,方法如下:

  1. 右键文件资源管理器点击Git Bash here,打开git命令行。
  2. 编辑ssh_config文件:vim /etc/ssh/ssh_config
  3. 找到GSSAPIAuthentication no配置项。
  4. 配置方法同上。

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_CNCharacter set改为GBK;点击ApplySave。再输入命令就不是乱码了,如下图:
在这里插入图片描述
注意: 情况1和情况2只能解决1种,建议解决情况2。

1.3.2. 情况2:远程库资源乱码(推荐解决)

非git命令中文显示正常,如:ls命令,等;但git命令无法显示中文,如:git status -s,等。如下图:
在这里插入图片描述
解决方案:
命令行窗口右键Options -> Text 界面,LocaleCharacter set为默认值(即空白);或Locale改为zh_CNCharacter set改为UTF-8;点击ApplySave

并修改全局配置,在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. 主分支解决冲突

  1. 去自己的工作分支
    git checkout work
  2. 获取最新修改
    git pull
  3. 工作
  4. 提交工作分支的修改
    git commit -m
  5. 回到主分支
    git checkout master
  6. 获取远程最新的修改,此时不会产生冲突
    git pull
  7. 合并工作分支的修改,若有冲突在此时解决
    git merge work
  8. 推送到远程库
    git push

1.4.2. 分支解决冲突(推荐)

在分支解决冲突,可以避免主分支出现冲突问题而造成的代码混乱。

  1. 去自己的工作分支
    git checkout work
  2. 获取最新修改
    git pull
  3. 工作
  4. 提交工作分支的修改
    git commit -a
  5. 回到主分支
    git checkout master
  6. 获取远程最新的修改,此时不会产生冲突
    git pull
  7. 回到工作分支
    git checkout work
  8. 合并主干的修改,如果有冲突在此时解决
    git merge master

    git rebase master(推荐)
  9. 回到主分支
    git checkout master
  10. 合并工作分支的修改,此时不会产生冲突。
    git merge work
  11. 推送到远程库
    git push

1.5. 使用rebase整理提交历史或合并分支

1.5.1. 整理提交历史

rebase操作可以把本地未push的分叉提交历史整理成直线;

rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比。

  1. 将提交历史整理成一条直线
    git rebase
  2. 合并最近的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点,可以保持整个分支树的完美线性。

  1. 先从 master 分支切出一个 feature1 分支,进行开发
    git checkout -b feature

    分支树如下图:
    分支图

  2. 这时,你的同事完成了一次修改(hotfix) ,并合并了 master 分支,此时 master 已经领先于你的 feature1 分支了:
    分支图

  3. 此时,我们想要同步 master 分支的改动

    方法一:merge方法
    git(feature1): git merge master
    在这里插入图片描述
    若执行git log命令,就会在记录里发现一些 merge 的信息,但我们想要保持一份干净的 commit 。这时候, git rebase 就派上用场了,详情见方法二。

    方法二:rebase方法
    git(feature1): git rebase master
    在这里插入图片描述
    commit 记录我们可以看出来, feature1 分支是基于 hotfix 合并后的 master ,自然而然的成为了最领先的分支,而且没有 mergecommit 记录,是不是感觉很舒服了。

    补充一下rebase的原理:
    首先, git 会把 feature1 分支里面的每个 commit 取消掉;
    其次,把上面的操作临时保存成 patch文件,存在 .git/rebase 目录下;
    然后,把 feature1 分支更新到最新的 master 分支;
    最后,把上面保存的 patch 文件应用到 feature1 分支上;

  4. rebase 的过程中,也许会出现冲突 conflict 。在这种情况, git 会停止 rebase 并会让你去解决冲突。在解决完冲突后,用 git add 命令去更新这些内容。

    注意,你无需执行 git commit,只要执行 continue
    git rebase --continue
    这样 git 会继续应用余下的 patch 补丁文件。

  5. 在任何时候,我们都可以用 --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(方法一)使用流程

  1. 在项目根目录打开Git Bash命令行(即Git Bash Here)。

  2. 创建.gitignore文件

    touch .gitignore
    
  3. 编辑.gitignore文件

    vim .gitignore
    

    示例内容:

    # 忽略当前目录的bin文件夹
    /bin/
    
    # 忽略当前目录的dir文件
    /dir
    
    # 忽略所有的test.txt文件
    test.txt
    
    # 忽略所有的html文件
    *.html
    
  4. 保存.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.objtools/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. 忽略规则示例),少数例外情况除外:

  1. 禁止负型
  2. 匹配目录的模式不会递归匹配该目录中的路径,因此使用尾随斜杠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。

属性

  1. text
    控制行尾的规范性。如果一个文本文件是规范的,则Git库汇总该文件的行尾总是LF。对于工作目录,除了text属性之外,还可以设置eol属性或core.eol配置变量。
  2. eol
    设置行末字符。
    eol=lf,入库时将行尾规范为LF,检出时禁止将行尾转换为CRLF
    eol=crlf,入库时将行尾规范为LF,检出时将行尾转换为CRLF。
  3. diff
    diff属性影响Git对特殊文件生成差异的方式。它可以告诉Git是否为路径生成文本补丁还是将路径视为二进制文件。它也可以影响在hunk头部显示的@@ -k,l +n,m @@,告诉Git使用外部命令来生成差异,或者是在生成差异之前让Git将二进制文件转换为文本文件。
  4. 其他属性即详情在这里不再介绍,请参照官方文档:gitattributes文档

优先级

  1. 同一个gitattributes文件中,按照行的先后顺序,优先级从上到下;如果一个文件的某个属性被多次设置,则后序的设置优先。
  2. 在一个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. 新建远程仓库

  1. 方式一(推荐): 借助网络平台建立远程仓库
    通过Web端(如GitHub,DevCloud等)新建仓库与分支,方法请自行查询或探索。在网页端可以复制SSH地址或HTTPS地址。后续会使用该地址与远程库进行连接,详情见2.1.7. 连接远程仓库

  2. 方式二: 局域网内搭建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命令克隆到本地就好,但是每次pullpush代码都需要输入账号和密码,这也是https方式的麻烦之处。而使用SSH url克隆却需要在克隆之前先配置和添加好SSH key,配置好后,使用方便。

注意:若使用HTTPS方式,则可直接跳到2.1.7. 连接远程仓库,若使用SSH方式,则需要继续看2.1.4. 设置SSH key

2.1.4. 设置SSH key(默认只设1个)

  1. 检查你电脑是否已经有 SSH key

    cd ~/.ssh 	// 跳转到ssh文件夹
    ls			// 列出文件夹中的文件
    

    .ssh文件夹不存在,则继续第2步创建SSH密钥;若存在 id_rsa.pub 或 id_dsa.pub 文件,则已存在SSH密钥,可以直接跳到第3步,或到第2步重置SSH密钥。

  2. 创建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个回车或自定义密码即可。

  3. 复制SSH公钥

    clip < ~/.ssh/id_rsa.pub
    

    cat ~/.ssh/id_rsa.pub
    
  4. 将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。步骤如下:

  1. 创建另一个密钥
    方法一:

    ssh-keygen -t rsa -C "yourEmail" -f ~/.ssh/test_rsa
    

    -f 直接指定文件路径及名称;之后的密码可以都是回车。

    方法二:

    ssh-keygen -t rsa -C "yourEmail"
    

    不要一路回车,让你选择在哪里选择存放SSH key的时候写个名字,比如github_rsa,之后的密码可以回车。

  2. 添加SSH密钥代理(临时)
    该方式是临时性的,重启ssh-agent服务后需要重新输入;若要永久保存设置(推荐),则需要配置config文件,详情见下一步,配置config文件,若配置了config文件,则无需再添加SSH密钥代理。

    添加SSH密钥代理步骤如下。
    打开ssh-agent:
    若为Windows系统,则命令为ssh-agent bash
    若其他系统,命令为ssh-agent -seval $(ssh-agent -s)

    添加私钥:

    ssh-add ~/.ssh/test_rsa
    
  3. 配置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的HostNamegithub.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
    
  4. 复制SSH公钥

    clip < ~/.ssh/id_rsa.pub
    

    cat ~/.ssh/id_rsa.pub
    
  5. 将SSH公钥粘贴到GitHub对应的位置(2种,步骤3-4已提及)并点击确定

2.1.6. 检测是否成功配置SSH key

  1. 默认SSH key检测:

    ssh -T [email protected]
    

    然后输入yes回车,若提示Hi, username! 则成功。

  2. 非默认SSH key检测(设有多个SSH key时):

    ssh -T git@[Host]
    

    Host~/.ssh/config 中的Host,用来代替HostName;若提示Hi, username! 则成功。

2.1.7. 连接远程仓库

即本地库与远程库的连接,为后续进行代码的pullpush做准备。需要使用2.1.1. 新建远程仓库中的SSH地址或HTTPS地址。

  1. 方式一(推荐):将远程仓库clone到本地

    git clone [url]
    

    [url]即远程库的SSH urlHTTPS url(地址),需从网页端的远程仓库复制。

  2. 方式二:本地仓库初始化并连接

    该方式先进行本地仓库的初始化,然后再进行远程库连接,该方法略微麻烦,效果和方式一相同。优点是可以自定义本地仓库文件夹的名称,并可将仓库文件夹中的代码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. 分支操作

  1. 移动到本地git仓库:cd [gitPath]
  2. 查看已有分支:git branch
    *和高亮的为当前分支
  3. 创建分支:git branch [branchname]
  4. 切换分支:git checkout [branchname]
    切换前需先进行提交(commit)。
  5. 创建并切换分支:git checkout -b [branchname]
  6. 删除分支:git branch -d [branchname]
    若没有合并分支,则不能删除。
  7. 强制删除分支: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. 上传代码

  1. git status
    查看项目当前的文件更新状态,也可以用git status -s简洁显示,一般与git diff命令配合使用,可省略。在任何时刻都可使用git statusgit 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)

  2. git add .
    将所有文件添加到缓存,也可使用git add [file1] [file2]单独添加文件。

    注意:被add的文件便可被git管理,没有被add的文件不会被git管理。

  3. git status -s
    再次查看项目当前的文件更新状态,可省略。

  4. git commit -m "[message]"
    将缓存提交到本地仓库,[message]为备注信息。若觉得每次都add后才能commit比较麻烦,可以使用git commit -am "[message]"来跳过add,但新文件和重命名文件不会被commit

    注意:要提前配好git仓库的用户名和邮箱才能正常使用该命令。

  5. 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. 方法二:
    命令行合并,步骤如下:
    (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系统环境下,步骤如下。

  1. 在公共服务器下创建远程仓库
    公共服务器(局域网服务器)可以是局域网中任意一台电脑,当做Git的远程仓库来使用,创建的远程仓库为空仓库。可供其他电脑进行代码的pullpush。步骤如下。

    (1) 创建一个文件夹,如public.git
    mkdir public.git
    (2) 进入该文件夹,建立裸仓库
    git init --bare

  2. 设置网络访问权限
    (1) 设置共享文件夹及共享权限
    设置 public.git 为共享文件夹。右键文件夹 —> 属性 —> 共享 —> 高级共享;设置共享名,添加;设置权限,编辑组和用户名,默认为Everyone,为Everyone添加允许完全控制权限。

    (2) 检测文件夹是否可访问
    确认在本机文件管理器中通过共享文件夹路径 \\IP地址\共享文件夹名称\\主机名称\共享文件夹名称 访问到,推荐使用IP地址,因为主机名可能出现重名冲突,而且速度更快,更精确。

    IP地址为本机(公共服务器)的IP地址,可通过Win10的 CMD命令提示符ipconfig命令查看,对应的网络适配器的IPv4地址即为本机的 IP地址

    主机名称可以右键桌面的 此电脑 图标,点击属性可以查看。也可在Git bash命令行中查看,@前面的即为主机名。

    注意: 共享文件夹名称可以与文件夹名称不同;共享文件夹路径的主机名称和共享文件夹名称不规范大小写;Git访问时,应该使用正斜杠 /

  3. 项目组成员连接局域网远程仓库
    项目组成员在自己的机器(包括公共服务器本机)上,参照以下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地址。

  4. 注意事项
    (1) 密码保护
    若共享设置中开启了密码保护,则项目组用户必须拥有公共服务器的用户账户(主机名)和密码(登录密码),才能访问共享文件夹。项目组成员在进行pullpush时需要填写用户账户和密码才能继续操作。

    控制面板\网络和 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. 删除分支

  1. git branch -d [branchname]
    普通删除,若没有合并分支,则不能删除。
  2. 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 pullgit 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 pullgit 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

方案三:手动备份
先备份好本地写好的代码,然后放弃本地修改,然后进行pullmerge,然后再把要修改的文件直接覆盖掉,然后再进行提交。

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 --forcegit push -f

关于commit_id(版本号):
当前版本为HEAD,上一个版本就是HEAD^HEAD~1,上上一个版本就是HEAD^^HEAD~2,当然往上100个版本写100个^并不容易,所以可以写成HEAD~100

可以使用HEADcommit_id进行版本回退。若记不清是上几个版本,可以使用git log可以查看提交历史及对应的commit_id,以便确定要回退到哪个版本。

版本号(commit_id)没必要写全,前几位就可以了(一般四位就够了),Git会自动去找。当然也不能只写前一两位,因为Git可能会找到多个版本号,就无法确定是哪一个了。

示例:
返回当前版本(即撤销更改):git reset --hardgit 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. 基本流程

  1. 本地仓库初始化(将当前目录设置为git仓库):git init

  2. 配置开发者的用户信息:

    git config --global user.name "username"
    git config --global user.email "[email protected]"
    

    以上为git全局的用户名和邮箱,不加--global即配置当前仓库的信息

  3. 创建和切换分支(初始化后默认为master分支):
    (1) 查看已有分支():git branch
    *和高亮的为当前分支
    (2) 创建分支:git branch [branchname]
    (3) 切换分支:git checkout [branchname]
    切换前需先进行提交(commit)。
    (4) 创建并切换分支:git checkout -b [branchname]

  4. 上传代码到本地库:
    (1) git status
    查看项目当前状态,也可以用git status -s简洁显示,一般与git diff命令配合使用,也可不查看状态直接进行git add。可在任何时刻使用git statusgit 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仓库的用户名和邮箱才能正常使用该命令。

  5. 合并分支:
    (1) 切换到主分支
    (2) 合并分支:git merge [branchname]
    branchname是要合并的分支名称

  6. 合并冲突
    在远程库的使用流程中也涉及,此处不再重复。

3.2. 扩展流程

扩展流程同远程库的扩展流程,这里不再赘述,内容如下:

  1. 删除分支
  2. 合并冲突
  3. 撤销更改
  4. 版本回退

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连接

  1. 下载安装Git Bash,下载地址:下载链接
  2. 打开Git Bash命令行,配置开发者的全局用户信息
    git config --global user.name "username"
    git config --global user.email "[email protected]"
    
    以上为git全局的用户名和邮箱,不加--global即配置当前仓库的信息。
  3. 打开IDEA软件,File/Configure -> Settings -> Version Control -> Git,在Path to Git executable中选择上一步Git Bash安装目录中的cmd文件夹下的git.exe文件。点击右侧的Test,会弹出Git Executed Successfully提示框。如下图:
    在这里插入图片描述
  4. 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. 建立本地库方式

  1. 创建本地库
    打开IDEA软件,VCS -> Import into Version Control -> Create Git Repository,然后选择相应的项目目录。之后工作目录的文件会变红。
  2. 添加远程库
    VCS -> Git -> Remote,或右键项目Git -> Repository -> Remote,点击右侧的加号,填写NameURLName默认为OriginURL为远程仓库地址,可以是HTTPSSSH方式。
  3. 添加到缓存
    右键项目Git -> add,或快捷键Ctrl+Alt+A,将文件添加到Git缓存。
  4. 提交及推送
    右键项目Git -> Commit Directory,或快捷键Ctrl+K,或点击软件右上方的Commit按钮;输入Commit Message,若想节省时间,可以取消勾选Porform code analysisCheck TODO
    之后点击弹窗下方的Commit,或下拉箭头中的Commit and Push (Ctrl+Alt+K),即可完成提交或推送。如下图:
    在这里插入图片描述
  5. 从远程库拉取代码
    右键项目Git -> Repository -> Pull,选择相应的RemoteBranchStrategy,之后点击Pull即可。
    或者直接点击软件右上方的Update Project (Ctrl+T),选择相应的Update Type,点击OK即可。
  6. 分支操作
    在软件右下角的Git:后面会显示当前分支,点击此处,可以显示所有分支并进行切换(checkout即为切换),也可进行创建新分支,删除分支等操作。如下图:
    在这里插入图片描述
  7. 合并
    右键项目Git -> Repository -> Merge Changes
  8. 处理冲突
    可以选择接受哪个更改,也可以先合并,然后再手动更改,更改之后要进行addcommitpush
  9. 栈操作
    入栈:右键项目Git -> Repository -> Stash Changes
    出栈:右键项目Git -> Repository -> Unstash Changes
  10. 查看提交历史
    右键项目Git -> Show History,即可查看提交历史。
  11. 版本回退
    右键项目Git -> Repository -> Reset HEAD,在To commit中填写HEAD^HEAD~1进行版本回退,点击Validate按钮可以查看回退的版本信息。
    注意: 当前版本为HEAD,上一个版本就是HEAD^HEAD~1,上上一个版本就是HEAD^^HEAD~2,当然往上100个版本写100个^并不容易,所以可以写成HEAD~100

4.3.3. 克隆远程库方式

  1. 从远程库克隆代码
    在IDEA的Welcome界面,选择Check out from Version Control -> Git,然后填写URLDirectoryURL为远程库地址,可以是HTTPSSSH方式。Directory为项目路径,必须是空文件夹。点击Clone即可克隆代码。

    在IDEA的项目界面下,VCS -> Git -> Clone或右键项目Git -> Repository -> Clone,可同样进入Clone界面。

  2. 其他操作
    其他操作与上一方式(建立本地库方式)相同。

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. 提取远程仓库

  1. 从远程仓库下载新分支与数据:
    git fetch [remotename] [branch]
    git merge [remotename] [branch]
    
    该命令执行完后需要执行git merge 远程分支到你所在的分支。在已经设置上流分支的情况下可省略 [remotename][branch]
  2. 从远端仓库提取数据并尝试合并到当前分支(推荐):
    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. 查看用户配置信息

  1. 查看所有
    git config -l
  2. 查看特殊
    git config user.name

6.2.2. 状态

  1. 查看状态
    git status
  2. 简要查看状态
    git status -s
  3. 几种状态如下:
    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 命令显示已写入缓存与已修改但尚未写入缓存的改动的区别。

  1. 尚未缓存的改动:git diff
  2. 查看已缓存的改动: git diff --cached
  3. 查看已缓存的与未缓存的所有改动:git diff HEAD
  4. 显示摘要而非整个 diff:git diff --stat

6.2.4. 分支

  1. 普通删除分支
    git branch -d [branchname]
  2. 强制删除分支
    git branch -D [branchname]

6.2.5. 缓存

  1. 将单个或多个文件上传到缓存
    git add [filename] [filename2]
    filename为文件的路径及名称,可使用相对路径,文件夹符号使用“/”。
  2. 丢弃工作区的修改
    git checkout -- [filename]
  3. 取消缓存已缓存的内容
    git reset HEAD [filename]
  4. 将文件从缓存区中移除
    git rm [filename]
    默认情况下,git rm file 会将文件从缓存区和你的硬盘中(工作目录)删除。 如果要在工作目录中留着该文件,可以使用命令: git rm --cached [filename]
  5. 将文件夹从缓存区中移除
    git rm -r [dirname]

6.2.6. 提交日志(log)

  1. 查看提交历史
    git log
  2. 查看未来的提交历史
    git relog

6.2.7. 重定基底(rebase)

  1. 合并提交(commit)
    (1) 将提交历史整理成一条直线
    git rebase
    (2) 合并最近4条合并记录
    git rebase -i HEAD~4
  2. 合并分支(在work分支下)
    git rebase master

6.2.8. Git栈(stash)

  1. git stash:备份当前的工作区的内容,从最近的一次提交中读取相关内容,让工作区保证和上次提交的内容一致。同时,将当前的工作区内容保存到Git栈中。
  2. git stash pop:从Git栈中读取最近一次保存的内容,恢复工作区的相关内容。由于可能存在多个Stash的内容,所以用栈来管理,pop会从最近的一个stash中读取内容并恢复。
  3. git stash list:显示Git栈内的所有备份,可以利用这个列表来决定从那个地方恢复。
  4. git stash clear:清空Git栈。此时使用gitg等图形化工具会发现,原来stash的哪些节点都消失了。

猜你喜欢

转载自blog.csdn.net/NSJim/article/details/93794675