Git手记

本地使用篇

工作区:前git状态
暂存区:add后的状态,列入git管理内容
仓库区:commit后的状态,被git归档
远程仓库:push后的状态,作为远程备份存在

配置

设置用户信息,这会作为提交代码时的信息
git config --global user.name [名字]
git config --global user.email xxx@xxx
不带global,只影响当前仓库,带global,影响全局默认配置。
消除路径转义(解决乱码)
git config --global core.quotepath false
设置默认主版本号名
git config --global init.defaultbranch 版本号名
pull时默认使用rebase模式
git config --global pull.rebase true
切换分支时,自动进行rebase(旧分支除外)
git config --global branch.autosetuprebase always
以下配置内容,需要保证全局变量中可以找到对应的程序
设置文本编辑器
git config --global core.editor xxx
设置差异分析工具
git config --global merge.tool vimdiff
Gnome用Meld,Qt用Kompare/Kdiff3
自动修改换行符实现跨平台兼容
git config --global core.autocrlf true|input
设置默认push模式
git config --global push.default matching|simple
matching 推送所有有对应的远程分支的本地分支
simple 只推送当前分支
设置忽略文件
git config --global core.excludesfile /path-to-file
缓存/永久保存/不缓存push账号密码
缓存账号密码,–timeout指定过期时间,默认900秒也就是15分钟
git config --global credential.helper cache [--timeout 900]
以文件形式长期保存账号密码,–file指定保存路径,默认~/.git-credentials%userprofile%/.git-credentials
git config --global credential.helper store [--file /path-to-file]
不缓存账号密码
git config --unset credential.helper
查看配置信息
git config --list
直接修改配置
git config --global -e
也可以去查看~/.gitconfig%userprofile%/.gitconfig
解决中文乱码:在配置文件中加入以下内容

1
2
3
4
5
6
[gui]
encoding = utf-8
[i18n]
commitencoding = utf-8
[svn]
pathnameencoding = utf-8

初始操作

创建仓库
git init [--bare]
选项:–bare 裸仓库,即不创建.git文件夹
添加文件
git add
剔除文件
git rm
移动文件
git mv
提交文件
git commit -m "信息" [-a]
-a 无视文件修改状态,也就是说修改了的文件不需要再次add直接上传
查看commit日志
git log
查看操作日志
git reflog
以列表形式显示文件更新记录
git blame 文件名
查看仓库信息
git status
查看暂存区文件列表
git ls-files
比较暂存区与工作区的文件差异
git diff
比较暂存区和最后一次提交的文件差异
git diff --cached

复原操作

HEAD表示当前版本,HEAD^HEAD~1表示上一个版本,以此类推
将暂存区复位到指定commit前的状态,不包括add, rm,不修改工作区文件,n=1时相当于撤销最后一次commit
git reset HEAD~n --soft
将暂存区复位到指定commit前的状态,包括add, rm,但不修改工作区文件
git reset HEAD~n [--mixed]
彻底重置当前状态,还原add过的工作区文件到选定的commit状态
git reset --hard HEAD~n
撤销工作区文件修改,恢复到暂存区状态
git checkout 文件名
reset --hard HEAD 文件名类似,但是不会修改当前分支,而是会作为新的commit提交
暂停当前工作
git stash
恢复之前一次工作
git stash pop

标签操作

标签,给当前状态的HEAD起个正式的版本号或名字
git tag -a "标签名" [-m "信息"]
上传指定版本,标签必须单独push,push代码时不会影响标签
git push 仓库名 标签名
显示所有的标签,必须push上游后才能显示
git tag
删除本地标签,这不会影响远程标签
git tag -d "标签名"
删除远程标签,这不会影响本地标签
git push 仓库名 --delete 标签名

分支操作

查看所有分支
git branch [--show-current]
创建一个分支
git branch "分支名"
创建一个和之前分支无关的全新分支
git checkout --orphan 分支名
切换当前分支
git checkout [-b] 分支名
带-b选项时,若不存在则先创建分支
删除已合并分支
git branch -d 分支名
强制删除分支
git branch -D 分支名
删除前请先退出分支
重命名分支
git branch -m [旧分支名] 新分支名
合并分支,将分支2合并到分支1,中途有冲突需要手动处理
git merge [分支名1] 分支名2 [--ff-only] [--no-ff] [--squash] [-m "合并信息"]
缺省分支1为当前分支
fast-forward是指在没有冲突的条件下直接省略commit进行合并
--ff-only表示仅当符合fast-forward条件时才merge
--no-ff表示完全不使用fast-forward
--squash表示把分支的commit历史压缩到一次
打开处理工具解决merge冲突
git mergetool
分支变基,将分支1完全转换为分支2,中途有冲突需要手动处理
git rebase [分支名1] 分支名2
缺省分支1为当前分支
原则
下游分支更新上游分支内容的时候使用rebase
上游分支合并下游分支内容的时候使用merge
冲突
出现冲突时,会提示发生冲突的文件,需要手动编辑对应文件进行处理

远程操作

以下链接均用长链接
显示远程仓库服务器
git remote -v
添加一个远程仓库
git remote add 仓库名 ssh://git@remote-server:port/path-to-project
克隆一个远程仓库
git clone ssh://git@remote-server:port/path-to-project
远程仓库若没有特别设置,仓库名默认为origin
重设远程仓库
git remote set-url 仓库名 ssh://git@remote-server:port/path-to-project
上传内容到远程
git push [--set-upstream|-u] 仓库名 [分支名:]远程分支名
git push [-f] # 已设置默认上游
设置上游联系(一键push)
git branch --set-upstream-to 仓库名/远程分支名
取消上游联系
git branch --unset-branch
显示远程仓库名
git remote show
显示远程仓库分支状况
git ls-remote
显示远程仓库详细情况
git remote show 仓库名
获取远程仓库更新
git fetch 仓库名 远程分支名:本地分支名
git fetch [--all] # 已设置默认上游
拉取远程仓库内容(并自动合并本地更改)
git pull 仓库名 远程分支名:本地分支名
git pull # 已设置默认上游
相当于先fetchmerge
建议使用这一条命令更新不同分支的内容
拉取远程仓库内容(并自动变基本地分支,不会产生merge点)
git pull --rebase 仓库名 远程分支名:本地分支名
git pull --rebase # 已设置默认上游
相当于先fetchrebase
建议使用这一条命令更新当前分支的内容
列出所有远程分支
git branch -r
列出分支映射信息
git branch -vv
删除远程分支
git push --delete 仓库名 远程分支名

杂项

ignore文件

在工作区创建.gitignore文件并配置,可以设置Git排除某些文件。该文件遵从通配符而不是正则表达式。
创建后执行git config core.excludesfile /path-to-file
git check-ignore -v file可以检测文件是否被排除

“loose object”错误

先删除出错的object文件夹,然后git fsck --full,最后查看git reflog

“Auto packing the repository for optimum performance”

Git会定期将对象打包为二进制文件以节省空间并提高传输效率。
用户可以执行git gc命令以手动进行这一行为。

服务器搭建篇

需求对比分析:

裸Git:直接使用Git创建仓库,依赖项最少,但功能最少,也最不直观,只支持SSH协议。
Github:使用最广泛的平台,免费提供基本服务,但是,代码托管服务不免费。每月 7 美金可以购买 5 个私有仓库,支持SSH和HTTP。
Gitea:轻量级的Git托管服务器,完全开源免费,支持SSH和HTTP。
Gitlab:提供完整的Git服务和CI/CD服务,有企业版和社区版两种,社区版可以免费离线使用,支持SSH和HTTP。

搭建流程

Git

  1. 安装Git
    apt install git[-core][-all]
    yum install git[-core][-all]
  2. 安全起见,创建一个独立的git组和用户
    groupadd git
    useradd git -m -g git -s /usr/bin/git-shell
    passwd git
  3. 可选,创建ssh密钥,实现免密push
    本地主机执行ssh-keygen -t rsa,然后将id_rsa.pub文件内容传入/home/git/.ssh/authorized_keys
  4. 创建一个工作目录,在目录中初始化仓库
    mkdir /srv/work.git 按照标准目录位置
    git init --bare
  5. 本地仓库新建一个git工作目录,将目录所有权交给git用户,然后初始化仓库
    chown git:git -R /srv/work.git
    必须保证目录所有权是git用户!!!否则会出现unpack错误!!!
    git init
  6. 添加文件到仓库中,每次添加都要这么做
    git add ./...
    修改文件后要确认,输入git commit -m "信息内容" -a
  7. 添加远程服务器
    git remote add [仓库名] ssh://git@remote-server:port/path-to-project
    注:port即为ssh端口号
  8. 推送更改
    git push [仓库名] [分支名]
    也可以先设置分支的上游关联git branch --set-upstream-to "仓库名"/"远程分支名"
    然后就可以使用git push一键push了
  9. 附录
    要提交修改,先git commit -m "信息内容" -agit push 仓库名 master
    要克隆项目,只需git clone ssh://git@remote-server:port/path-to-project
    方便起见,可以先在服务器创建仓库,然后本地clone空仓库,这样会自动设置上游。

Gitea

一个轻量级的Git托管服务器,是Gogs的一个Fork,目的是通过社区提供更多功能,没有自带CI/CD功能,但是可以通过插件实现。
和Gogs大量重合,可以无缝迁移。

本机搭建

安装Git和SQLite(也可以用MySQL和PostgreSQL)
apt install git[-core][-all] sqlite3
yum install git[-core][-all] sqlite

安全起见,创建一个独立的git组和用户
groupadd git
useradd git -m -g git -s /usr/bin/git-shell
passwd git

安装
gitea | Giteago-gitea/gitea下载最新版二进制程序
程序默认没有执行权限,chmod a+x gitea赋予执行权限
然后移动至标准目录mv gitea /usr/local/bin/

创建目录
创建配置文件目录,并修改权限
mkdir /etc/gitea
chown -R git:git /etc/gitea
创建资料文件目录,并修改权限
mkdir /var/lib/gitea
mkdir /var/lib/gitea/custom
mkdir /var/lib/gitea/data
chown -R git:git /var/lib/gitea
创建日志文件目录
mkdir /var/log/gitea
chown -R git:git /var/log/gitea
可选:禁止一般用户对日志文件目录的读权限
chmod -R o-wrx /var/log/gitea

配置服务
创建/etc/systemd/system/gitea.service,一个模板如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[Unit]
Description=Gitea (Git with a cup of tea)
After=syslog.target
After=network.target

# 别忘了添加数据库服务依赖,当然如果使用SQLite的话就不需要了
# MySQL
# Wants=mysql.service
# After=mysql.service

# PostgreSQL
# Wants=postgresql.service
# After=postgresql.service

[Service]
# 如果你的仓库中文件数量巨大,导致出现500错误,请设置这一行取消限制
# LimitNOFILE=524288:524288
RestartSec=2s
Type=simple
User=git
Group=git
WorkingDirectory=/var/lib/gitea/
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
Restart=always
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea

[Install]
WantedBy=multi-user.target

之后,使用systemctl enable --now gitea.service启动服务

Gitea初始化安装
如图所示
注意,域名应设置为与本机直接绑定的域名,如果没有请设为缺省值localhost
如果设置了反向代理,URL应设置为协议://实际访问域名或IP:实际访问端口/
![[gitea.png]]

基本配置到这里就结束了,以下为一些按需进行的自定义配置

离线模式
如果你想禁用一切外部CDN,仅使用本地主机,请修改/etc/gitea/app.ini,在[server]段修改以下内容:

1
2
[server]
OFFLINE_MODE = true # 不使用CDN加载头像和资源文件

设置SSH
如果你对SSH进行了反向代理,或者不想使用SSH,请修改/etc/gitea/app.ini,在[server]段修改以下内容:

1
2
3
4
5
[server]
SSH_DOMAIN = example.com # 请设置为实际访问的域名或IP
...
DISABLE_SSH = false # 设为true可以彻底禁止SSH
SSH_PORT = 22 # 请设置为实际访问的SSH端口

添加SSH公钥
进入头像->设置->SSH/GPG密钥->增加密钥,将公钥文件*.pub的内容拷贝进下方内容栏,设置名称后保存。

重新设置数据库
修改/etc/gitea/app.ini,在[database]段修改以下内容

1
2
3
4
5
6
7
8
9
[database]
DB_TYPE = sqlite3 # 数据库类型,可选sqlite3, mysql, postgresql
HOST = 127.0.0.1:5432 # 数据库服务器Socket
NAME = gitea # 数据库的库名
USER = gitea # 数据库用户名
PASSWD = # 数据库密码
SSL_MODE = disable # MySQL或PostgreSQL数据库是否启用SSL模式
CHARSET = utf8mb4 # 仅当数据库为MySQL时有效,设置字符编码,可选uft8或utf8mb4
PATH = data/gitea.db # SQLite数据文件保存路径

设置HTTPS
修改/etc/gitea/app.ini,在[server]段添加以下内容

1
2
3
4
5
6
7
8
9
10
[server]
PROTOCOL = https
ROOT_URL = https://localhost:3000/ # 协议部分改为https
HTTP_PORT = 3000
CERT_FILE = 证书路径
KEY_FILE = 私钥路径

# 设置HTTP重定向
REDIRECT_OTHER_PORT = true
PORT_TO_REDIRECT = 3080

如果你使用ACME,还要在[server]段添加以下内容:

1
2
3
4
5
6
7
8
9
[server]
# 配置ACME
ENABLE_ACME = true
ACME_ACCEPTTOS = true
# ACME提供商网站,留空默认使用Let's Encrypt
;ACME_URL = https://ca.example.com/acme/acme/directory
;ACME_CA_ROOT = /path/to/root_ca.crt
ACME_DIRECTORY = https
ACME_EMAIL = email@example.com

然后,在[session]段添加以下内容

1
2
3
4
5
[session]
PROVIDER = memory|file # 绘画临时文件保存在内存或文件中
PROVIDER_CONFIG = data/sessions # 如果保存在文件中,那么指定保存目录
COOKIE_SECURE = true # 强制使用HTTPS进行会话控制
GC_INTERVAL_TIME = 86400 # 会话遗忘失效的时间

设置注册
修改/etc/gitea/app.ini,在[service]段修改以下内容

1
2
3
4
5
6
7
8
[service]
REGISTER_EMAIL_CONFIRM = false # 注册时需要邮箱验证
DISABLE_REGISTRATION = false # 完全禁用注册,只能通过管理员手动添加用户
ENABLE_CAPTCHA = false # 注册时需要RECAPTCHA验证码
REQUIRE_SIGNIN_VIEW = false # 所有页面都必须登录后才可以访问
DEFAULT_KEEP_EMAIL_PRIVATE = false # 默认将新注册用户的邮箱地址设为私密
DEFAULT_ALLOW_CREATE_ORGANIZATION = true # 默认允许新用户创建组织
DEFAULT_ENABLE_TIMETRACKING = true # 默认允许仓库进行时间记录

设置仓库
修改/etc/gitea/app.ini,在[repository]段添加以下内容

1
2
3
4
5
ROOT = /path    # 设置存放git项目的根目录
SRIPT_TYPE = bash|sh # 服务器使用的Shell
ANSI_CHARSET = utf-8 # 默认字符编码
FORCE_PRIVATE = false # 强制所有git项目都是私密的
MAX_CREATION_LIMIT = -1 # 每个用户创建的git项目最大数量,-1表示无限制

设置头像
修改/etc/gitea/app.ini,在[picture]段添加以下内容

1
2
3
4
5
6
7
8
9
10
DISABLE_GRAVATAR = true    # 完全禁用在线头像,只使用本地头像
GRAVATAR_SOURCE = gravatar # 在线头像来源,可以是提供方名例如gravatar,duoshuo,也可以填链接如https://dn-qiniu-avatar.qbox.me/avatar/
ENABLE_FEDERATED_AVATAR = false # 启用Libravatar头像联盟支持
AVATAR_UPLOAD_PATH = data/avatars # 本地用户头像文件存储路径
AVATAR_MAX_WIDTH = 4096 # 头像最大宽度,单位像素
AVATAR_MAX_HEIGHT = 3072 # 头像最大高度,单位像素
AVATAR_MAX_FILE_SIZE = 1048576 # 头像最大文件大小,单位Mb
REPOSITORY_AVATAR_UPLOAD_PATH = data/repo-avatars # 本地仓库头像文件存储路径
REPOSITORY_AVATAR_FALLBACK = none|random|image # 找不到仓库头像时的处理方式,分别为不显示头像,随机生成头像和使用指定头像
REPOSITORY_AVATAR_FALLBACK_IMAGE = data/repo-avatars/default.png # 指定找不到仓库头像时使用的头像

设置附件
修改/etc/gitea/app.ini,在[attachment]段添加以下内容

1
2
3
4
5
6
[attachment]
ENABLED = true # 是否允许用户在issue和request中上传附件
ALLOWED_TYPES = */* # 允许上传的附件类型,可以使用MIME格式,也可以指定后缀,用逗号分隔。默认为*/*即允许所有类型
MAX_SIZE = 4 # 附件最大文件大小,单位MB
MAX_FILES = 5 # 单词最大上传附件数量
PATH = data/attachments # 附件存储路径

设置日志
修改/etc/gitea/app.ini,在[log]段添加以下内容

1
2
3
4
5
6
7
8
9
ROOT_PATH = /var/log/gitea    # 日志文件的保存目录
MODE = console|file # 日志文件的记录模式,默认为console即输出到终端,设置为file表示保存到文件
LEVEL = info # 日志的记录等级,可选trace, debug, info, warn, error, critical, fatal, none
ENABLE_SSH_LOG = false # 记录SSH日志,会一并记录到默认日志中
ENABLE_XORM_LOG = true # 记录XORM日志,会一并记录到默认日志中
DISABLE_ROUTER_LOG = false # 不记录路由日志
ROUTER = console|file # 路由日志的记录模式,默认为console
ENABLE_ACCESS_LOG = false # 记录访问日志,格式为NCSA
ACCESS = console|file # 访问日志的记录模式,默认为file

[database]段修改以下内容

1
2
[database]
LOG_SQL = false # 记录SQL语句日志

设置定时任务
修改/etc/gitea/app.ini,在[cron]段添加以下内容

1
2
3
[cron]
ENABLED = true # 是否运行定期任务
RUN_AT_START = true # 是否启动时运行一次

重新设置LFS
修改/etc/gitea/app.ini,在[server]段修改以下内容

1
2
[server]
LFS_START_SERVER = true # 启用LFS

[lfs]段添加以下内容

1
2
[lfs]
PATH = data/lfs # 存放LFS文件的路径,留空不启用LFS

Nginx反向代理
创建Nginx site文件,写入以下内容:

1
2
3
4
5
6
7
8
9
10
11
server {
listen 80;
server_name [域名];
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

location / {
proxy_pass http://127.0.0.1:3000;
}
}

邮件通知
修改/etc/gitea/app.ini,在[mailer]段添加以下内容

1
2
3
4
5
6
[mailer]
ENABLED = true
HOST = SMTP服务器IP:端口
FROM = 发送邮箱
USER = SMTP用户
PASSWD = SMTP密码

然后,可以在[service]段修改以下内容

1
2
[service]
ENABLE_NOTIFY_MAIL = false # 启用提醒邮件,会在创建工单等行为时发送

配置fail2ban
创建日志过滤配置文件/etc/fail2ban/filter.d/gitea.conf,写入以下内容:

1
2
3
[Definition]
failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>
ignoreregex =

创建监狱服务配置文件/etc/fail2ban/jail.d/gitea.conf,写入以下内容:

1
2
3
4
5
6
7
8
[gitea]
enabled = true
filter = gitea
logpath = /var/lib/gitea/log/gitea.log
maxretry = 10
findtime = 3600
bantime = 900
action = iptables-allports

重新安装
修改/etc/gitea/app.ini,在[security]段修改以下内容

1
2
[security]
INSTALL_LOCK = false

重启服务后,会重新出现安装页面

Gitlab

Gitlab有友好的网页控制台和图形化操作功能,官方提供了企业版(付费)和社区版(免费),搭建可以使用本机安装或Docker。

本机搭建

  1. 首先去gitlab - Repositories
    下载对应的软件包。
  2. 安装后修改/etc/gitlab/gitlab.rb,本地配置把external_url改为IP:portURL:port,设置Gitlab接收请求的IP或域名。内置的Nginx服务器默认监听0.0.0.0:80,修改nginx['listen_addresses']nginx['listen_port']可以改变。如果不使用内置的Nginx,可以修改web_server['external_users']设置外部服务器用户。设置nginx['redirect_http_to_https']以确保HTTP访问重定向至HTTPS
  3. 如果有防火墙,注意配置对应端口开放
  4. 执行gitlab-ctl reconfigure应用配置
  5. 启动Gitlabgitlab-ctl start
  6. 初次启动需要等待较长时间,期间显示502为正常现象

Docker搭建

  1. 拉取Gitlab的CE版镜像docker pull gitlab/gitlab-ce
  2. 运行以下命令启动Gitlab容器
    1
    2
    3
    4
    5
    6
    7
    8
    docker run --detach \
    -p 辅助端口:443 主要端口:80 辅助端口:22 \
    --name gitlab \
    --restart always \
    --volume /var/opt/gitlab/config:/etc/gitlab \
    --volume /var/opt/gitlab/logs:/var/log/gitlab \
    --volume /var/opt/gitlab/data:/var/opt/gitlab \
    gitlab/gitlab-ce:latest
  3. 如果有防火墙,需要配置相应的端口开放
  4. 访问本机IP+端口

SVN

使用SVNAdmin 2.0。

Docker搭建

  1. 拉取镜像docker pull witersencom/svnadmin
  2. 启动临时容器docker run -d --name temp --privileged witersencom/svnadmin:2.4.3 /usr/sbin/init
  3. 拷贝配置文件
    1
    2
    3
    4
    cd /home/
    docker cp svnadmintemp:/home/svnadmin ./
    docker cp svnadmintemp:/etc/httpd/conf.d ./svnadmin/
    docker cp svnadmintemp:/etc/sasl2 ./svnadmin/
  4. 删除临时容器docker rm -f temp
  5. 正式启动容器
    1
    2
    3
    4
    5
    6
    7
    docker run -d -p 80:80 -p 3690:3690 \
    -v /home/svnadmin/:/home/svnadmin/ \
    -v /home/svnadmin/conf.d/:/etc/httpd/conf.d/ \
    -v /home/svnadmin/sasl2/:/etc/sasl2/ \
    --privileged \
    --name svnadmin \
    witersencom/svnadmin
  6. 进行文件授权
    1
    2
    docker exec -it svnadmin bash
    chown -R apache:apache /home/svnadmin