1. Git常见QA问题
1.1. 错误1: terminal prompts disabled
通过go get -u xx/xx
更新包时候,遇到fatal: could not read Username for 'https://xx.com': terminal prompts disabled
问题
原因是默认情况下,git会使用https进行clone,会提示要输入用户名和密码,推荐使用ssh免密clone,参考 https://golang.org/doc/faq#git_https
解决方案,可以通过git命令配置通过 ssh替代https进行代码clone: git config --global --add url."git@github.com:".insteadOf "https://github.com/"
上述处理,等同于配置~/.gitconfig
,增加类似下述代码,有的注意http和https都要配置
[url "git@git.xxx.com:"]
insteadOf = https://git.xxx.com/
[url "git@git.xxx.com:"]
insteadOf = http://git.xxx.com/
2. 1 Git Server服务配置
2.1. 1.1 git用户创建
// root创建gitman账号+5(可以忽略)
useradd git
passwd git
// 登入gitman账号 & 初始化基本ssh环境
ssh-kengen
// 将需要访问git srv服务器的用户的公钥加入到受信认证清单
$ cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys
$ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys
$ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys
2.2. 1.2 git空仓库初始化
// 在/srv/git仓库下初始化一个空仓库
$ cd /srv/git
$ mkdir project.git
$ cd project.git
$ git init --bare
Initialized empty Git repository in /srv/git/project.git/
// 本地Mac操作,初始化一个本地仓库,加入remote源,并推送到remote源
$ cd myproject
$ git init
$ git add .
$ git commit -m 'Initial commit'
$ git remote add origin git@gitserver:/srv/git/project.git
$ git push origin master
// 可以支持受信的用户clone访问了
$ git clone git@gitserver:/srv/git/project.git
$ cd project
$ vim README
$ git commit -am 'Fix for README file'
$ git push origin master
2.3. 1.3 git-shell安全设定
由于我们是useradd加入的普通账户,当前所有这些用户也可以登录服务器并以git用户身份获得Shell,我们可以通过git-shell
命令代替bash或csh该帐户的登录shell:
// 加入git-shell到 etc/shells 中
$ cat /etc/shells # see if git-shell is already in there. If not...
$ which git-shell # make sure git-shell is installed on your system.
$ sudo -e /etc/shells # and add the path to git-shell from last command
// 修改过git账户的默认shell为git-shell
$ sudo chsh git -s $(which git-shell)
// 在MAC端测试
$ ssh git@gitserver
fatal: Interactive git shell is not enabled.
hint: ~/git-shell-commands should exist and have read and execute access.
Connection to gitserver closed.
// 防止git的使用账户,转发端口等行为,需要进一步在`authorized_keys`进行限制,加上`no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty` 选项设定
$ cat ~/.ssh/authorized_keys
no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAABAQCB007n/ww+ouN4gSLKssMxXnBOvf9LGt4LojG6rs6h
PB09j9R/T17/x4lhJA0F3FR1rP6kYBRsWj2aThGw6HXLm9/5zytK6Ztg3RPKK+4kYjh6541N
YsnEAZuXz0jTTyAUfrtU3Z5E003C4oxOj6H0rfIF1kKI9MAQLMdpGW1GYEIgS9EzSdfd8AcC
IicTDWbqLAcU4UpkaX8KyGlLwsNuuGztobF8m72ALC/nLF6JLtPofwFBlgc+myivO7TCUSBd
LQlgMVOFq1I2uPWQOkOWQAHukEOmfjy2jctxSDBQ220ymjaNsHT4kgtZg2AYYgPqdAv8JggJ
ICUvax2T9va5 gsg-keypair
// 再次在MAC端测试
$ ssh git@gitserver
PTY allocation request failed on channel 0
fatal: Interactive git shell is not enabled.
hint: ~/git-shell-commands should exist and have read and execute access.
Connection to ioio.cool closed.
3. 2 Git常用Tips
3.1. 2.1 命令行PS提示
// 克隆仓库
git clone https://github.com/magicmonty/bash-git-prompt.git ~/.bash-git-prompt --depth=1
// 加入到 ~/.bashrc:
if [ -f "$HOME/.bash-git-prompt/gitprompt.sh" ]; then
GIT_PROMPT_ONLY_IN_REPO=1
source $HOME/.bash-git-prompt/gitprompt.sh
fi
// 重载bash:
. ~/.bashrc
3.2. 2.2 Submodule操作
参考:https://git-scm.com/book/zh/v2/Git-工具-子模块
3.2.1. 2.2.1 submodule 初始化添加
// 在已有的git仓库中使用子模块,add后会在当前目录下,新增一个名为DbConnector的库
$ git submodule add https://github.com/chaconinc/DbConnector
// git status查看,新增文件
.gitmoudules
DbConnector
// cat .gitmodules,该文件随版本控制,同时modules中的url应该可以被访问
// 其中的配置,也可以通过git config submodule.DbConnector.url newUrl来覆盖
[submodule "DbConnector"]
path = DbConnecor
url = https://github.com/chaconinc/DbConnector
// 在主仓库提交,git commit后,看到160000模式,该模式为特殊模式,即将提交项纪录,而非纪录为文件或文件夹
$ git commit -am 'added DbConnector module'
[master fb9093c] added DbConnector module
2 files changed, 4 insertions(+)
create mode 100644 .gitmodules
create mode 160000 DbConnector
3.2.2. 2.2.2 含submodule模块项目clone
// 克隆含子模块的项目
$ git clone https://github.com/chaconinc/MainProject
...
// 进入项目,并查看到包含.gitmodules文件,同时相关gitmodules对应仓库文件为空
// 初始化子模块配置,并从该项目中抓取所有数据,并检出府项目中的提交
$ git submodule init
$ git submoduel update
// init+update上述两步可以合成一步(在项目clone后,执行这个)
$ git submodule update --init
// 如果子模块还有嵌套的子模块,需要加上--recursive
$ git submodule update --init --recursive
// clone+init+update,可以合成一步,即在clone一个含submodules项目适合,直接加入`--recurse-submoduels`参数
$ git clone --recurse-submodules https://github.com/chaconinc/MainProject
Tips: 为安全起见,如果 MainProject 提交了你刚拉取的新子模块,那么应该在
git submodule update
后面添加--init
选项,如果子模块有嵌套的子模块,则应使用--recursive
选项
3.2.3. 2.2.3 进入submodule目录,进行拉取更新操作
// 从子模块远端拉取上游修改
cd DbConnector
git fetch
git merge origin/master
// 回到主项目,执行diff查看更新差异,其他类型诸如log和short
// 可以通过git config --global diff.submodule diff来配置,配置后,可以在全局的.git/config配置中看到
git diff --submodule=diff
// fetch+merge上述两步,可以合成一步,完成子模块更新并更新
git submodule update --remote
3.2.4. 2.2.4 submodules模块中的url有变更的情况
// 如果不想每次都指定--recurese-submodules选项,可以通过`git config submodule.recurse true`
$ git pull --recurse-submodules
// 若直线pull或者submodule更新失败,需要同步修改git submodules的URL
将新的URL同步到本地中
$ git submodule sync --recursive
$ git submodule update --init --recursive
3.2.5. 2.2.5 submodules模块处于游离状态
在主项目中,运行了git submodule update,从子模块仓库更新了子项目后,子仓库会留在游离HEAD状态,意味着本地没有工作分支跟踪改动,这样即使后续再子项目文件中做了修改,提交后也可能会丢失,因为没有合并到主分支中。
为此,需要先checkout到指定分支,拉取最新的远程工作分支,在合并本地子项目中的内容(可以先做commit或者stash)
$ cd DbConnector
$ git checkout master
$ git stash
$ git submodule update --remote --merge
$ git pop (解决冲突)
$ git add .
$ git commit -m 'commit message'
// 回到主项目,同步submodule提交的更新内容(需要加上--merge或者--rebase),否则会重置成为一个游离态的HEAD
// 若忘记加--merge或者--rebase,子模块目录变为游离分支后,重新checkout会到master分支即可
git submodule update --remote --merge
// 若子模块有更新,又没有提交子模块内容,同时又不小心在主模块提交了子模块的更新,这样其他人无法更新到子模块内容,因此需要
$ git push --recurse-submodule=check
// 这里可以通过 `git config push.recurseSubmodules check`,来避免遗忘参数
// 默认参数是on-demand,是他的默认行为
3.2.6. 2.2.6 submodules的技巧
foreach,每个子模块中任意命令
// 子项目均暂存
$ git submodule foreach 'git stash'
// 子项目+分支快速创建
$ git submodule foreach 'git checkout -b featureA'
// 主项目+所有子项目的差异
$ git diff; git submodule foreach 'git diff'
// 设置别名
$ git config alias.supdate 'submodule update --remote -merge'
3.3. 2.3 测试git账号连通性
ssh -T git@gitlab.com
3.4. 2.4 仅下载Github上的指定目录内容(转svn)
- 从浏览器URI中找到要下载的内容,比如
https://github.com/computer-system-education/os-syllabi/tree/master/material/tsinghua-os-2019-spring
- 将
tree/master
转成trunk
- 转成
svn checkout
(稍微会等一会):svn checkout https://github.com/computer-system-education/os-syllabi/trunk/material/tsinghua-os-2019-spring
完整的URL格式说明:
如果您对
master分支
感兴趣,请trunk
改用。所以完整的路径是trunk/foldername
如果您对
foo分支
感兴趣,请branches/foo
改用。完整的路径看起来像branches/foo/foldername
Protip:如果愿意,您可以
svn ls
在下载之前查看可用的标签和分支
4. 3 Git使用
4.1. 3.1 图示操作


4.2. 3.2 分支管理
// 拉取并切换到远程指定分支
git fetch origin hotfix-20151118-v1
git checkout hotfix-20151118-v1
// 本地创建一个新分支
git checkout -b newbranch
4.3. 3.3 merge合并
// 1. 切换到合并分支(即最终代码组合的的那个分支,假定为develop)
git checkout develop
// 2. 合并,并形成新的提交点
git merge feature-x
// 3. 合并过程中可能出现冲突,配置命令行冲突解决工具vimdiff
git mergetool --tool=vimdiff
4.4. 3.4 rebase变基
// 1. 创建一个特性分支&做开发修改
git checkout -b feature-x
// 2. 将feature-x内容重放到develop
git checkout develop
git rebase feature-x
// 3. 可能存在冲突,解决冲突(三方合并)
[fix origin code] && git add .
// 4. 继续rebase
git rebase --continue
git rebase --skip (忽略当次patch,并继续)
5. 4 丢弃修改
// 丢掉本地所有更新
git reset --hard
6. 5 日志内容查看
// 上次修改的
git log -2 --pretty=short
// 上次修改的内容
git log -p -1
// 看文件
git log --name-only
git log -5 --pretty=medium --name-only