文章目录
- 简介
- 安装
- linux离线安装
- windows安装
- 用户配置
- 简单使用
- 设置用户名
- 提交至暂存区
- 提交delete变更
- git add . 与 git add *
- 向远程库push
- push -f
- 分支
- 建空白分支
- 分支合并
- 分支冲突
- 从远程库pull
- 当远程库版本跟本地仓库不一致
- 直接pull
- 尚未pull
- 暂存区
- 文件移除
- gitignore
- gitignore修改未生效
- 知识点暂存
- git reset
- 保存用户名和密码(免密提交)
- 问题
- unable to read askpass response
- git fatal: Unable to find remote helper for ‘https‘
- error: src refspec 分支名 does not match any
20220628笔记迁移
简介
这里就先不简介了,版本控制系统嘛就是
安装
linux离线安装
参考文献:
- linux离线安装git
首先是下载:git镜像下载地址
官方下载地址
虽然是镜像,但是仍然下的很慢。(原来是公司的网下的慢)
然后解压文件:
tar -vxf /usr/local/git/git-2.9.5.tar.gz
然后进git的解压目录,再编译&安装:
./configure --prefix=/usr/local/git
make && make install
--prefix
后面就是git要正式安装的路径,可以选择自己需要的目录。
最后配置环境变量:
vi ~/.bachrc
export PATH=$PATH:/xxx/soft/git/bin/
source /etc/profile
验证是否安装成功:
git --version
能打出来版本信息就说明成功。
windows安装
Windows下Git下载安装详细图文教程(亲测有效
镜像下载地址:windows下载地址
官网下载地址:https://git-scm.com/
去下载download for windows,下下来是exe版本,用着会更舒服。
用户配置
命令格式:
git config user.name
全局配置文件:
Git 提供了一个叫做 git config 的工具,专门用来配置或读取相应的工作环境变量。这些环境变量,决定了 Git 在各个环节的具体工作方式和行为。这些变量可以存放在以下三个不同的地方:
-
/etc/gitconfig:系统中对所有用户都普遍适用的配置。git config --system读写的就是这个文件。
-
~/.gitconfig:用户目录下的配置文件只适用于该用户。git config --global读写的就是这个文件。
-
.git/config:当前项目的Git目录中的配置文件(也就是工作目录中的.git/config文件),仅仅针对当前项目有效。
每一个级别的配置都会覆盖上层的相同配置,所以.git/config里的配置会覆盖/etc/gitconfig中的同名变量。在 Windows 系统上,Git会找寻用户主目录下的.gitconfig文件。主目录即$HOME变量指定的目录,一般都是C:\Documents and Settings\$USER
关于.git/config
文件里的设置:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = http://10.xx.xx.xx:80/xxx/td_realtime.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "live_sql"]
remote = origin
merge = refs/heads/live_sql
[user]
name = xxx
email = xxx@xxx.com
可以在这里添加user信息,用来重写全局的设置。
简单使用
这里先简单介绍一些常用功能的指令。
初始化一个本地仓库:git init
之后当前目录就会出现一个名为.git
的目录,里面含有Git仓库所必须的文件,这些文件是Git仓库的骨干。
将一个文件添加进提交暂存区:git add 文件名
将暂存区统一刷进本地仓库:git commit -m "注释,用来标记本次提交的目的"
查看提交暂存区的情况,以及被追踪文件的修改情况:git status
或者用一种更简介的状态简览情况:git status --short
查看提交历史,感觉是本地仓库的提交历史:git log
新增远程仓库:git remote add origin http://xxx/td_realtime.git
其中origin是本地给予的远程仓库的简名。
提交到远程仓库的固定分支:git push origin master
其中有几个参数,-u和-f,前者表示记录了push到远端分支的默认值,下次直接git push
就可以,-f
则是强制推送,忽略本地仓库和远程仓库的差异。
master是分支名,远程仓库和本地仓库都需要有这个分支名。
查看本地设置过的远程仓库:git remote -v
创建分支:git branch newBranch
将head切换到指定分支:git checkout newBranch
设置用户名
git config --global user.name "xxx"
git config --global user.email "xxx"
上面是全局设置,本质上是修改~/.gitconfig
这个文件。
git config --local user.name "xxx"
git config --local user.email "xxxx"
这个是本地化配置,在当前项目文件夹中执行,本质上是修改.git/config
这个文件
提交至暂存区
提交delete变更
正常来讲,提交一个文件到暂存区是:git add 文件名
但是这种方式是提交不了delete变更的,比如说下面这种:
# On branch tlife31
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: monitor/check-all-job-daily.sh
# deleted: xxx/tools/tk_app_hp_tmp_for_century2.java
如果要提交delete变更,需要带上-A
参数,即git add -A xxx/tools/tk_app_hp_tmp_for_century2.java
,才能把deleted变更提交到暂存区。
这是为什么呢?
因为git add
在不带参数的时候,就等价于git add --ignore-removal <pathspec>
,会忽略那些从你的工作树中移除的路径。
所以我们需要使用git add -A
,即等价于git add --all <pathspec>
,才会允许记录这些移除变更。
git add . 与 git add *
参考文献:
- git add . 和 git add * 区别以及 git commit -m 与 git commit -am 的区别
git add .
的坑比较大。
git add .
会把本地所有untrack的文件都加入暂存区,并且会根据.gitignore做过滤;
git add *
会忽略.gitignore把任何文件都加入;
这两个,其实哪个都尽量不要轻易用,除非你真的知道你在干啥。
向远程库push
push -f
参考文献:
- git中push -f是啥意思
在git中,push -f的意思是"强制更新",是"push --force"的缩写。
这个命令很危险,当本地仓库跟远程仓库版本不一致时,会使用本地仓库版本覆盖掉远程仓库版本,远程提交会被删除。
举例说明:
首先,本地库和远程库保持一致,都只有一个1.txt
;
然后在远程库新建一个文件,命名为2.txt
,这时候远程库是:
同时提交日志为:
但是本地库还是只有一个1.txt
,这时候两个库版本就不一致了。
接着我在本地库直接新建一个3.txt
,commit之后push origin master
提交到远程库,这时候会报错:
$ git push origin master
To http://xxxxx/tlife_single.git
! [rejected] xxx-> xxx(fetch first)
error: failed to push some refs to 'http://xxxxx/tlife_single.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
意思是推送失败,远程库现在处于一个比你高的版本。
这时候我们换成push -f origin master
来强制推送,推送成功了,显示:
$ git push -f origin master
Enumerating objects: 8, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 12 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (8/8), 704 bytes | 352.00 KiB/s, done.
Total 8 (delta 1), reused 0 (delta 0)
remote:
remote: To create a merge request for master, visit:
remote: http://xxxxx/tlife_single/-/merge_requests/new?merge_request%5Bsource_branch%5D=master
remote:
To http://xxxxx/tlife_single.git
+ 59b4d6e...c53ee1f master-> master(forced update)
可以看到,是一个forced update
。
然后再去远程仓库去看:
之前的那个2.txt
没了。然后再看提交日志,现在变成了:
可以看到上次在远程库上做的那个"add new file"的提交没了。
之前的提交记录全都没了!所以轻易不要用push -f
,除非你知道你正在做什么,否则会造成极其严重的后果。
分支
查看本地分支:git branch
带星号的是当前head指向的分支,或者说当前工作目录所处的分支
查看远程分支:git branch -r
查看所有分支(本地分支+远程分支):git branch -a
删除本地分支:git branch -d 分支名
新建分支xxx:git branch xxx
新建分支xxx,并将当前分支设置为xxx:git checkout -b xxx
切换到分支xxx:git checkout xxx
建空白分支
参考文献:
- 如何快速在 Git 中创建一个空分支(孤立分支) 不要跟着学rm,他喵的那个是删除本地文件,可以使用
git rm --cached 文件名
的方式解除对指定文件名的追踪。
空白分支,不继承任何提交,也没有父节点,就是完完整整空白的,也叫做孤儿分支。
一般来讲,可以在这个分支里专门存放图片等与代码无关的东西。
使用git checkout -b
命令创建的分支是有父节点的,这意味着新的分支包含了历史提交(git log
可以看到一大堆以前的历史提交),所以我们可以使用:git checkout --orphan 分支名
来创建孤立分支,或者说空白分支。
如果空分支没有任何文件被提交的话,使用git branch
是看不到空分支的,除非commit一次,这时候再git branch
就可以看到了这个空分支。
分支合并
参考文献:
- 使用分支——Git Merge命令 写的很好
分支合并,是指将不同的两条分支合并成一条分支,基本是围绕git merge
这个指令来的。
merge会将其他分支合并到当前所在的工作分支上,需要注意的是,当前工作分支的内容会由于merge操作产生更新,但是其他分支则完全不受影响。所以如果合并后,你不需要另一条分支了,可以使用git branch -d 分支名
来删除。
根据两个分支之间的提交历史路径,可以把分支合并分成两类:
- 快进合并
- 三路合并
什么时候可以使用快进合并?
当前工作分支到合并目标分支之间的提交历史是线性路径时,可以进行快进合并。那什么是线性路径呢,就是说当前工作分支是目标分支曾经所处的一个版本,如图:
这种情况下,并不需要真实的合并两个分支,只需要把当前分支的顶端指针快速移动到目标分支的顶端即可,这就是所谓的快进。然后把目标分支中的中的提交历史都合并到当前分支里。合并之后就成了:
那如果两个分支的提交历史不是线性的,而是有分叉的,该怎么办呢?
这时候git使用的,就是三路合并
三路合并算法需要使用一个专门的commit来整合两边的提交历史。至于为什么叫三路,是因为如果想生成一个合并后的commit,需要用到3个commits:两个分支顶端的commit、以及它们的共同祖先commit;
但是无论是快进合并,还是三路合并,都是直接调用git merge
就可以,对用户来讲,这两种合并的区别,是无感知的。
# 首先切到主分支(需要保留的分支)
git checkout main
# 在主分支上,合并other_branch分支
git merge other_branch
# 删除other_branch分支
git branch -d other_branch
当然,不删也行,可以保留。
在三路合并中,如果两个分支没有对同一个文件做过修改,那么git merge就可以正常运行,不会有问题;
但是如果他们有对同一个文件做过修改的话,那就会出现分支冲突,从而报错。
分支冲突
参考文献:
- git合并分支冲突解决 很好
- 使用分支——Git Merge命令
分支冲突一般是要合并分支的时候出现的,要合并的两个分支都修改了同一个文件的同一部分内容,导致git无法确定应该使用哪个版本的内容。
下面讲解一个案例:
我有两个一模一样的分支:
- wlh_ttss_1
- wlh_ttss_2
每个分支都有一个空白的3.txt
,接下来我会对两个分支里的3.txt
做不同的修改,最后尝试合并两个分支。
git checkout wlh_ttss_1
vi 3.txt
新增以下内容
wanglh
pengsc
提交到本地仓库:
git commit -m "wanglh,pengsc"
然后修改另一个分支wlh_ttss_2:
git checkout wlh_ttss_2
vi 3.txt
新增内容:
huangping
现在我想在将wlh_ttss_2合并到wlh_ttss_1分支:
首先需要将工作分支切成wlh_ttss_1:
git checkout wlh_ttss_1
尝试使用git merge自动合并分支:
$ git merge wlh_ttss_2
Auto-merging 3.txt
CONFLICT (content): Merge conflict in 3.txt
Automatic merge failed; fix conflicts and then commit the result.
自动合并失败,原因是这两个分支里对3.txt
都做过修改,git不知道该保留哪个,于是报错通知你一下,把压力给到你这边。
合并失败后,当前分支的状态会被改成merging
:
出现冲突时,文件内冲突的表现:
=======
上面的,是当前所处分支的内容;下面的,是另一个分支的内容;
<<<<<<< HEAD
wanglh
pengsc
=======
huangping
>>>>>>> wlh_ttss_2
出现了合并冲突后,可以使用git status
来查看出现冲突的路径,即处于unmerged
状态的文件:
$ git status
On branch wlh_ttss_1
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: 3.txt
那怎么解决呢?
只能手动处理了,保留其中一部分,或者是合并两部分,比如说我把文件改成这样:
wanglh
pengsc
huangping
当你手动修改完所有文件里的冲突之后,使用git add
把这些文件重新提交到暂存区,并commit:
可以看到,当文件被重新放到暂存区后,文件会被取消unmerged状态,等重新commit之后,当前分支也从merging
状态恢复正常了。
现在我们再看wlh_ttss_1分支的提交日志:
可以看到,现在wlh_ttss_2的提交日志也被合并到了wlh_ttss_1分支里,而且解决完冲突后,最新提交的那个版本,上面明晃晃的写着Merge:
,表示是从后面两个版本合并而来的。
需要注意的是,合并只影响了wlh_ttss_1分支,wlh_ttss_2分支没有任何变化,包括它的git log,也不会包含新的提交。
从远程库pull
当远程库版本跟本地仓库不一致
参考文献:
- git操作:如何解决本地版本与远程仓库版本不一致的问题
- git本地与远程冲突处理
直接pull
日常举例:
当前所处wlh_ttss_1分支,本地库和远程库都有3.txt
,但是内容不同
本地库3.txt
:
wanglh
pengsc
huangping
远程库3.txt
:
shenys
这时候如果我不知道远程库版本跟我不一样,也没有验证过,而是直接从远程仓库拉取最新版本:git pull ttss wlh_ttss_1
会报错:
$ git pull ttss wlh_ttss_1
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From http://xxx/tlife_test
* branch wlh_ttss_1 -> FETCH_HEAD
79eb205..001fd0d wlh_ttss_1 -> ttss/wlh_ttss_1
Auto-merging 3.txt
CONFLICT (content): Merge conflict in 3.txt
Automatic merge failed; fix conflicts and then commit the result.
这时候怎么办呢?
跟处理分支冲突是一样的,手动修改冲突文件的内容,然后重新git add 3.txt
以及git commit
。
尚未pull
再上一个案例,仍然是wlh_ttss_1分支,本地库和远程库原先是一模一样的。
现在我修改一下远程库上3.txt
的内容:
wanglh
再修改下本地库上3.txt
的内容(提不提交本地库都可以):
shenys
不做pull,而是先执行git fetch ttss wlh_ttss_1
来验证了一下远程库跟本地库的版本差异。
这表示远程的分支有了新的版本,你的本地库版本跟远程库不一样了,这时候该怎么办呢?
看你是保大还是保小了
方法一:保留远程库,覆盖本地的修改。
$ git reset --hard ttss/wlh_ttss_1
HEAD is now at 13c738d Update 3.txt,wanglh77
这样操作后,本地所做的所有修改都会被覆盖!!!一定要谨慎使用!!!
现在再看本地的3.txt,里面的内容就变成了shenys
这里的git reset
实际上是删除了本地版本,使用远程版本强制更新本地,然后把head指向刚刚下载的最新版本。
方法二:在本地合并修改,推送合并版本
首先将远程仓库的最新版本下载到本地,命名为tmp:
$ git fetch ttss wlh_ttss_1:tmp
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 1 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From http://xxx/tlife_test
* [new branch] wlh_ttss_1 -> tmp
68ee703..9abc087 wlh_ttss_1 -> ttss/wlh_ttss_1
然后查看tmp分支跟本地分支有什么不同:
可以看到,跟tmp分支相比,本地分支删除了wanglh,但是新增了shenys。
然后我们将tmp分支合在本地分支上:
这里可能会报这个错误:
这是因为本地的这次修改还没有commit到本地仓库,commit一下就好。
git commit -m
完成之后,再次合并tmp分支,这时候会出现:
报错了,不用慌,按照之前讲的"分支冲突",手动处理之后commit就可以,一样的。
最后将合并后的版本push到远程库,现在远程库跟本地库的版本就又保持一致了!
别忘记删除tmp分支,因为没用了。
附注:第二种方式里,如果修改还没有提交到本地仓库的话,也可以基于git stash
暂存本地修改,更新远程库的内容到本地,再恢复出刚才暂存的修改,最后处理内容冲突:
git stash
git pull
git stash pop
#再处理冲突
相比于我上面讲的那种,这种方式的好处在于,最后远程仓库的提交里,会少一次记录,就只会有一次合并完后的提交。
暂存区
从暂存区中删除某项文件(即不再追踪此文件):
git rm --cached 文件名
git rm -r --cached 文件夹名/
文件移除
参考文献:
- git rm 删除以及清空暂存区
两种方式:
git rm 文件名
git rm --cached 文件名
前者是把当前工作目录下的文件也删除掉,并且会将本次delete修改提交到暂存区。
后者是只从暂存区删除文件,其实就是变成未跟踪状态,后续仍然可以手动add进暂存区。这个用的更频繁一些。
gitignore
参考文献:
- 在git上传过程中,忽略无后缀文件
- .gitignore的用法
- Git 开发必备 .gitignore 详解!【建议收藏】
- Git- .gitignore匹配规则及注意事项
- .gitignore文件通用模板
给一些常用的:
# Ignore all
*
# Unignore all with extensions
!*.*
# Unignore all dirs
!*/
### Above combination will ignore all files without extension ###
斜杠后面紧跟两个连续的星号,表示多级目录:src/**/file
gitignore修改未生效
两种原因:
- 指定文件已经跟踪过了;
- 关于规则顺序的问题;
第一种情况下,需要通过git rm 文件名 --cached
将目标文件先从暂存区抛弃掉,即改变它为未追踪状态;
第二种情况下,如果.gitignore里是这么写的:
# 过滤所有sql文件
*.sql
# 保留所有带后缀的文件
!*.*
这时候,所有的sql文件仍然会被追踪,因为生效原则有点像就近原则。
知识点暂存
git reset
这个是用来做版本回退的
git reset
这个区分带不带参数--hard
,有两种使用方式:
git reset <版本节点ID>
git reset --hard <版本节点ID>
节点ID就是git log之后,每个版本上面的commit,如:
commit 445017d338f46a9c3ec6f9f433b81685e1aafa6f
当加参数--hard
时,不但将本地的head指针指向了上一个版本,而且还重置了暂存区的内容,重置了本地工作区的内容。这个别乱用。
当不加参数--hard
时,只是将git仓库中的节点进行了回退,本地工作区并不影响。
git reset --hard详解
保存用户名和密码(免密提交)
git每次更新或者提交代码时都需要输入用户名和密码,太过麻烦,可以选择记住密码,下次就不用再输了。
首先修改记住密码的全局设定:
git config --global credential.helper store
或者不加--global
,即:
git config credential.helper store
不加--global
表示只对当前仓库生效,加上就是全局生效了。建议不要加global,以仓库为单位区分对待。
之后进行git pull,会让你再输入用户名和密码,这次输入之后,系统将会记住你的用户名和密码,以后就不用输了。
再之后,在C:/用户/你的用户名/.gitconfig
文件中,会多两行:
[credential]
helper=store
同时会多一个C:/用户/你的用户名/.git-credentials
文件,这里面就以明文形式存储了用户名和密码,这里就不贴了。
或者是在git config credential.helper store
的时候加上一个--file
参数来指定.git-credentials
文件的存储路径,如:
git config credential.helper store --file ~/xxx/.git-credentials
参考文献:
-
GIT提交时不用输入用户名密码的方法 推荐先看这个
-
git每次更新或者提交代码时都需要输入用户名和密码问题解决
问题
unable to read askpass response
参考文献:
- unable to read askpass response from '/usr/libexec/openssh/gnome-ssh-askpass错误
- git https方式pull、push时,提示:error: unable to read askpass response from '/usr/libexec/openssh/gnome-ssh
git 基于https的方式进行pull、push的时候,会提示:
(gnome-ssh-askpass:88340): Gtk-WARNING **: 17:05:41.969: cannot open display:
error: unable to read askpass response from ‘/usr/libexec/openssh/gnome-ssh-askpass’
解决方法是关闭SSH_ASKPASS即可。
$ unset SSH_ASKPASS
之后提交正常。
To prevent it in future, you can add the above line in your .bashrc or .bash_profile.
git fatal: Unable to find remote helper for ‘https‘
参考文献:
- git push 提示 git fatal: Unable to find remote helper for ‘https‘ 错误 这个写的非常好,感恩
- git报错 ‘remote-http‘ is not a git command. See ‘git --help‘ 这个跟上面其实是一个问题,第一个问题是低版本git的报错方式,第二个问题是高版本git报错,其实都是一个原因引起的。
这是一个很惨烈的问题。出现在跟远程仓库连接的时候,比如说push,无法通过http的方式跟远程仓库通信。
核心原因是当前机器没有安装curl。
如果你的机器有网,且有root权限的话,可以使用:
yum install curl-devel
或者apt等。
但是如果没网,或者没有root权限该怎么办?
离线安装,并编译。
首先从curl官方地址下载最新的curl包
其次解压,然后make安装:
./configure --prefix=/xxx/soft/curl/
make && make install
然后重新编译git:
./configure --prefix=/xxx/soft/git/ --with-curl=/xxx/soft/curl/
make && make install
注意这里一定要带上--with-curl
参数,指定到上面安装的curl目录,git只有与curl库做了link之后,才能正常编译带上http功能。
之所以一定要带上,其实还是因为没有root权限,拥有root权限自动安装的时候会安装到默认目录,--with-curl
会自己找。
error: src refspec 分支名 does not match any
出现这个的原因很杂。
我出现这个原因是在push的时候,执行以下代码出错:
git push -uf xx xx167
但是本地没有xx167分支,当前处于的是master分支。