GitLab初识以及代码迁移
一.理论概述
1.什么是gitlib
Gitlab 是一个基于Git实现的在线代码仓库托管软件,你可以用Gitlab自己搭建一个类似于Github一样的系统平台,一般搭建gitlab私服就是用在公司的内部,
Gitlab 功能就是能够对代码的提交审核和问题跟踪,这个对于软件工程质量的管理是至关重要的,而且GitLab拥有web界面,更加直观.安装GitLab建议4GB内存以上
Gitlab分为社区版(CE) 和 企业版(EE)大多数的公司还是会选择社区版
其实gitlab的原理就是git的原理,GitHub不是也是基于Git的吗,笔者在这篇文章介绍过
2.GitLab服务构成
分别是:
- Nginx:静态Web服务器
- gitlab-shell:用于处理Git命令和修改authorized keys列表
- gitlab-workhorse:轻量级的反向代理服务器(这个是个敏捷的反向代理,它会处理一些大的HTTP请求,比如文件的上传下载,其他的请求会反向代理给Gitlab Rails应用)
- logrotate:日志文件管理工具
- postgresql:数据库
- redis:缓存数据库
- sidekiq:用于在后台执行队列的任务
- unicorn:Gitlab Rails应用是托管在这个服务器上面的
3.Git对比SVN
Git | SVN | |
---|---|---|
代码管理方式 | 分布式,本地就可以用,保存历史痕迹,不用担心污染服务器 | 集中式 |
分支 | Git中代码仓库只是一个文件快照,对分支做操作非常迅速 | 相当于是版本库中的文件的复制,操作分支速度较慢 |
代码管理 | GitLab可以通过web界面很方便的管理权限等等 | 还是传统操作方式 |
二.部署
1.简单操作GitLab
- 部署GitLab
[root@gitlab ~]# vim /etc/yum.repos.d/gitlab-ce.repo
[gitlab-ce]
name=Gitlab CE Repository
baseurl=https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el$releasever/
gpgcheck=0
enabled=1
[root@gitlab ~]# yum clean all
[root@gitlab ~]# yum -y install gitlab-ce
#安装最新版本
#yum install gitlab-ce-x.x.x
#安装指定版本
[root@gitlab ~]# vim /etc/gitlab/gitlab.rb
external_url 'http://192.168.111.3'
#修改配置文件,改为本机ip,或者可以解析情况下修改为域名
[root@gitlab ~]# gitlab-ctl reconfigure
#重新加载配置文件
[root@gitlab ~]# cat /opt/gitlab/version-manifest.txt | head -1
gitlab-ce 12.0.3
#查看GitLab版本
客户端浏览器输入192.168.111.3
访问web界面测试
设置密码
然后使用root用户登录,密码为刚才自定义的
将在GitLab创建的仓库克隆到本地
[root@gitlab ~]# git config --global user.name "joinbest"
[root@gitlab ~]# git config --global user.email "joinbest@163.com"
#这里配置的用户名和邮箱并不是说要在某服务器上注册,而是类似于一种标识符的存在
创建一个README文件并且同步到远程仓库
[root@gitlab ~]# git clone http://192.168.111.3/root/joinbest.git
正克隆到 'joinbest'...
warning: 您似乎克隆了一个空版本库。
[root@gitlab ~]# cd joinbest
[root@gitlab joinbest]# touch README.md
[root@gitlab joinbest]# git add README.md
[root@gitlab joinbest]# git commit -m "add README"
[master(根提交) 2cb80d4] add README
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README.md
[root@gitlab joinbest]# git push -u origin master
Username for 'http://192.168.111.3': root #远程仓库用户
Password for 'http://root@192.168.111.3': #远程仓库密码
Counting objects: 3, done.
Writing objects: 100% (3/3), 210 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To http://192.168.111.3/root/joinbest.git
* [new branch] master -> master
分支 master 设置为跟踪来自 origin 的远程分支 master。
- GitLab常用命令
sudo gitlab-ctl start
# 启动所有 gitlab 组件;
sudo gitlab-ctl stop
# 停止所有 gitlab 组件;
sudo gitlab-ctl restart
# 重启所有 gitlab 组件;
sudo gitlab-ctl status
# 查看服务状态;
sudo gitlab-ctl reconfigure
# 启动服务;
sudo vim /etc/gitlab/gitlab.rb
# 修改默认的配置文件;
gitlab-rake gitlab:check SANITIZE=true --trace
# 检查gitlab;
sudo gitlab-ctl tail
# 查看日志;
三.项目实践:SVN代码迁移至GitLab
疑问点:项目迁移,新建一个Git项目,把SVN代码复制过去不就可以了吗?但是为了保留之前的历史提交记录,我们得用更安全保守可靠的方式来进行代码迁移
环境
主机名 | ip | 角色信息 |
---|---|---|
gitlab | 192.168.111.3 | GitLab服务器 |
svn | 192.168.111.4 | SVN服务器 |
1.Linux下部署SVN服务器及简单实用
[root@svn ~]# yum -y install subversion
#安装
[root@svn ~]# mkdir -p /application/svndata/joinbest
[root@svn ~]# mkdir -p /application/svnpasswd
#后面配置会用到
[root@svn ~]# svnadmin create /application/svndata/joinbest/master
[root@svn ~]# svnadmin create /application/svndata/joinbest/dev
[root@svn ~]# svnadmin create /application/svndata/joinbest/test
#创建分支
[root@svn ~]# vim /application/svndata/joinbest/master/conf/svnserve.conf
anon-access = none
#不允许匿名访问
auth-access = write
#通过授权的用户允许写操作
password-db = /application/svnpasswd/passwd
#用户以及密码文件
authz-db = /application/svnpasswd/authz
#授权文件
[root@svn ~]# cp /application/svndata/joinbest/master/conf/svnserve.conf /application/
svndata/joinbest/dev/conf/cp:是否覆盖"/application/svndata/joinbest/dev/conf/svnserve.conf"? yes
[root@svn ~]# cp /application/svndata/joinbest/master/conf/svnserve.conf
/application/svndata/joinbest/test/conf/cp:是否覆盖"/application/svndata/joinbest/test/conf/svnserve.conf"? yes
#每个分支都需要配置,直接复制过去
[root@svn ~]# cp /application/svndata/joinbest/master/conf/passwd /application/svnpasswd/
[root@svn ~]# cp /application/svndata/joinbest/master/conf/authz /application/svnpasswd/
#复制到我们制定的目录里使用
[root@svn ~]# vim /application/svnpasswd/passwd
[users]
manager=123456
dev=123456
tom=123
bob=123
#格式为"用户名=密码"
[root@svn ~]# vim /application/svnpasswd/authz
[groups]
testgroup=tom,bob
#在[groups]标签下定义一个组,并且定义包含哪些用户
[joinbest/master:/]
manager = rw
dev = r
#该标签表示joinbest仓库下的master分支,各个用户的权限,manager用户有读和写,dev用户只有读权限
[joinbest/dev:/]
dev = rw
manager = r
[joinbest/test:/]
@testgroup = r
manager = rw
[root@svn ~]# svnserve -d -r /application/svndata/
[root@svn ~]# ps aux | grep svn
root 59559 0.0 0.0 197684 1040 ? Ss 15:34 0:00 svnserve -d -r /application/svndata/
#启动
2.Linux下SVN客户端进行测试及简单使用
[root@gitlab ~]# yum install -y subversion
#安装
[root@gitlab ~]# svn checkout svn://192.168.111.4/joinbest/master ./master
认证领域: <svn://192.168.111.4:3690> ea5d88c8-24e7-41d8-b26d-a646288dc380
“root”的密码:
认证领域: <svn://192.168.111.4:3690> ea5d88c8-24e7-41d8-b26d-a646288dc380
用户名: manager
“manager”的密码:
-----------------------------------------------------------------------
注意! 你的密码,对于认证域:
<svn://192.168.111.4:3690> ea5d88c8-24e7-41d8-b26d-a646288dc380
只能明文保存在磁盘上! 如果可能的话,请考虑配置你的系统,让 Subversion
可以保存加密后的密码。请参阅文档以获得详细信息。
你可以通过在“/root/.subversion/servers”中设置选项“store-plaintext-passwords”为“yes”或“no”,
来避免再次出现此警告。
-----------------------------------------------------------------------
保存未加密的密码(yes/no)?yes
取出版本 0。
#将文件checkout到本地目录
[root@gitlab ~]# svn checkout svn://192.168.111.4/joinbest/dev ./dev
[root@gitlab ~]# svn checkout svn://192.168.111.4/joinbest/test ./test
- 添加代码文件
[root@gitlab ~]# ll | grep -E 'test|dev|master'
drwxr-xr-x 3 root root 18 7月 7 18:20 dev
drwxr-xr-x 3 root root 18 7月 7 18:17 master
drwxr-xr-x 3 root root 18 7月 7 18:21 test
[root@gitlab dev]# cd /root/dev/
[root@gitlab dev]# echo testdev > dev.txt
[root@gitlab dev]# svn add dev.txt
A dev.txt
[root@gitlab dev]# svn commit -m '2019年7月7日18:29:42' dev.txt
[root@gitlab dev]# cd /root/master
[root@gitlab master]# echo testmaster > master.txt
[root@gitlab master]# svn add master.txt
A master.txt
[root@gitlab master]# svn commit -m '2019年7月7日18:29:42' master.txt
正在增加 master.txt
传输文件数据.
提交后的版本为 1。
[root@gitlab master]#cd /root/test
[root@gitlab test]# echo testtest > test.txt
[root@gitlab test]# svn add test.txt
A test.txt
[root@gitlab test]# svn commit -m '2019年7月7日18:29:42' test.txt
正在增加 test.txt
传输文件数据.
提交后的版本为 1。
正在增加 dev.txt
传输文件数据.
提交后的版本为 1。
[root@gitlab dev]#
[root@gitlab dev]# cd ../master/
[root@gitlab test]# svn list svn://192.168.111.4/joinbest/master
master.txt
[root@gitlab test]# svn list svn://192.168.111.4/joinbest/dev
dev.txt
[root@gitlab test]# svn list svn://192.168.111.4/joinbest/test
test.txt
#svn服务端也有了这些文件了
3.先将SVN服务器上代码迁移至Git
yum安装Git没有git-svn功能,需要用到源码安装的Git
[root@gitlab ~]# yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-devel -y
#依赖包
#cd /usr/local/src
#wget https://www.kernel.org/pub/software/scm/git/git-1.9.4.tar.gz
#tar xf git-1.9.4.tar.gz
#cd git-1.9.4
#make prefix=/usr/local/git all
#make prefix=/usr/local/git install
#rm -rf /usr/bin/git
#ln -s /usr/local/git/bin/git /usr/bin/git
[root@gitlab git-1.9.4]# git version
git version 1.9.4
[root@gitlab git-1.9.4]# yum -y install subversion-perl perl-Digest-MD5
#代码迁移要用到这些
创建svn代码备份到本地的目录
[root@gitlab git-1.9.4]# mkdir /backup
[root@gitlab git-1.9.4]# cd /backup/
克隆svn分支
[root@gitlab backup]# git svn clone --no-metadata svn://192.168.111.4/joinbest/master/ /backup/master/
#根据提示输入相应密码
[root@gitlab backup]# git svn clone --no-metadata svn://192.168.111.4/joinbest/test/ /backup/test/
[root@gitlab backup]# git svn clone --no-metadata svn://192.168.111.4/joinbest/dev/ /backup/dev/
[root@gitlab backup]# tree
.
├── dev
│ └── dev.txt
├── master
│ └── master.txt
└── test
└── test.txt
[root@gitlab backup]# cat dev/dev.txt
testdev
[root@gitlab backup]# cat master/master.txt
testmaster
#可以看到代码已经克隆完整
在GitLab创建新仓库,并且将分支添加到GitLab上
推送代码到GitLab上
[root@gitlab ~]# cd /backup/master/
[root@gitlab master]# git branch
* master
[root@gitlab master]# git branch joinbest
[root@gitlab master]# git checkout joinbest
切换到分支 'joinbest'
[root@gitlab master]# git branch
* joinbest
master
#新建一个分支,这样提交到GitLab上的分支名称会是joinbest这个可以自定义
[root@gitlab master]# git add *
[root@gitlab master]# git commit -m "master commit"
位于分支 joinbest
无文件要提交,干净的工作区
[root@gitlab master]# git remote add origin http://192.168.111.3/root/pro.git
[root@gitlab master]# git push -u origin joinbest
Username for 'http://192.168.111.3': root
Password for 'http://root@192.168.111.3':
Counting objects: 3, done.
Writing objects: 100% (3/3), 252 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote:
remote: The private project root/pro was successfully created.
remote:
remote: To configure the remote, run:
remote: git remote add origin http://192.168.111.3/root/pro.git
remote:
remote: To view the project, visit:
remote: http://192.168.111.3/root/pro
remote:
To http://192.168.111.3/root/pro.git
* [new branch] joinbest -> joinbest
分支 joinbest 设置为跟踪来自 origin 的远程分支 joinbest。
[root@gitlab master]# cd /backup/dev/
[root@gitlab dev]# git branch
* master
[root@gitlab dev]# git branch joinbest_dev
[root@gitlab dev]# git checkout joinbest_dev
切换到分支 'joinbest_dev'
[root@gitlab dev]#
[root@gitlab dev]# git add *
[root@gitlab dev]# git commit -m "dev branch commit"
位于分支 joinbest_dev
无文件要提交,干净的工作区
[root@gitlab dev]# git remote add origin http://192.168.111.3/root/pro.git
[root@gitlab dev]# git push -u origin joinbest_dev
Username for 'http://192.168.111.3': root
Password for 'http://root@192.168.111.3':
Counting objects: 3, done.
Writing objects: 100% (3/3), 244 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote:
remote: To create a merge request for joinbest_dev, visit:
remote: http://192.168.111.3/root/pro/merge_requests/new?merge_request%5Bsource_branch%5D=joinbest_dev
remote:
To http://192.168.111.3/root/pro.git
* [new branch] joinbest_dev -> joinbest_dev
分支 joinbest_dev 设置为跟踪来自 origin 的远程分支 joinbest_dev。
[root@gitlab dev]# cd /backup/test/
[root@gitlab test]# git branch
* master
[root@gitlab test]# git branch test
[root@gitlab test]# git checkout test
切换到分支 'test'
[root@gitlab test]# git add *
[root@gitlab test]# git commit -m "test branch commit"
位于分支 test
无文件要提交,干净的工作区
[root@gitlab test]#
[root@gitlab test]# git remote add origin http://192.168.111.3/root/pro.git
[root@gitlab test]# git push -u origin test
Username for 'http://192.168.111.3': root
Password for 'http://root@192.168.111.3':
Counting objects: 3, done.
Writing objects: 100% (3/3), 248 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote:
remote: To create a merge request for test, visit:
remote: http://192.168.111.3/root/pro/merge_requests/new?merge_request%5Bsource_branch%5D=test
remote:
To http://192.168.111.3/root/pro.git
* [new branch] test -> test
分支 test 设置为跟踪来自 origin 的远程分支 test。
四.项目实践:GitLab之间的代码迁移(环境迁移)
主机名 | ip | 角色信息 |
---|---|---|
labtest | 192.168.111.3 | 测试环境GitLab |
lab | 192.168.111.4 | 生产环境GitLab |
labtest还是用上面已经搭建好的GitLab环境
- 部署GitLab
[root@lab ~]# vim /etc/yum.repos.d/gitlab-ce.repo
[gitlab-ce]
name=Gitlab CE Repository
baseurl=https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el$releasever/
gpgcheck=0
enabled=1
[root@lab ~]# yum clean all
[root@lab ~]# yum -y install gitlab-ce
#安装最新版本
#yum install gitlab-ce-x.x.x
#安装指定版本
[root@lab ~]# vim /etc/gitlab/gitlab.rb
external_url 'http://192.168.111.4'
#修改配置文件,改为本机ip,或者可以解析情况下修改为域名
[root@lab ~]# gitlab-ctl reconfigure
#重新加载配置文件
[root@lab ~]# cat /opt/gitlab/version-manifest.txt | head -1
gitlab-ce 12.0.3
#查看GitLab版本
在labtest将用到的配置文件复制到lab机器上
[root@labtest ~]# cp /etc/gitlab/gitlab.rb{,.bak}
[root@labtest ~]# cp /var/opt/gitlab/nginx/conf/nginx.conf{,.bak}
[root@labtest ~]# cp /etc/postfix/main.cf{,.bak}
[root@labtest ~]# scp /etc/gitlab/gitlab.rb root@192.168.111.4:/etc/gitlab/
[root@labtest ~]# scp /var/opt/gitlab/nginx/conf/nginx.conf root@192.168.111.4:/var/opt/gitlab/nginx/conf/
[root@labtest ~]# scp /etc/postfix/main.cf root@192.168.111.4:/etc/postfix/
[root@labtest ~]# vim +334 /etc/gitlab/gitlab.rb
gitlab_rails['backup_path'] = "/var/opt/gitlab/backup"
#待会我们使用备份工具时,输出文件的保存路径
gitlab_rails['backup_keep_time'] = 604800
#备份文件的保存时间,604800为7天
[root@labtest ~]# gitlab-ctl reconfigure
#重新加载配置
[root@labtest backup]# cd /backup/
[root@labtest backup]# gitlab-rake gitlab:backup:create
#使用以上命令会在/var/opt/gitlab/backup目录下创建一个名称类似为1562501710_2019_07_07_12.0.3_gitlab_backup.tar的压缩包, 这个压缩包就是Gitlab整个的完整部分, 其中开头的1393513186是备份创建的日期.
[root@labtest backup]# pwd
/var/opt/gitlab/backup
[root@labtest backup]# ls
1562501710_2019_07_07_12.0.3_gitlab_backup.tar
- Gitlab 自动备份
也可以通过crontab
使用备份命令实现自动备份:
sudo su -
crontab -e
加入以下, 实现每天凌晨2点进行一次自动备份:
0 2 * * * cd /backup/ && /opt/gitlab/bin/gitlab-rake gitlab:backup:create
- Gitlab迁移
迁移如同备份与恢复的步骤一样, 只需要将老服务器/var/opt/gitlab/backup
目录下的备份文件拷贝到新服务器上即可(如果你没修改过默认备份目录的话). 但是需要注意的是新服务器上的Gitlab的版本必须与创建备份时的Gitlab版本号相同. 比如新服务器安装的是最新的7.60版本的Gitlab, 那么迁移之前, 最好将老服务器的Gitlab 升级为7.60在进行备份.
[root@labtest backup]# scp /var/opt/gitlab/backup/1562501710_2019_07_07_12.0.3_gitlab_backup.tar root@192.168.111.4:/root/
在另一台机器将该备份移动到指定目录下
[root@lab ~]# mv /root/1562501710_2019_07_07_12.0.3_gitlab_backup.tar /var/opt/gitlab/backups/
[root@lab ~]# chmod 777 /var/opt/gitlab/backups/1562501710_2019_07_07_12.0.3_gitlab_backup.tar
[root@lab ~]# gitlab-ctl stop unicorn
ok: down: unicorn: 0s, normally up
[root@lab ~]# gitlab-ctl stop sidekiq
ok: down: sidekiq: 1s, normally up
#将数据库和队列先关闭
[root@lab ~]# gitlab-rake gitlab:backup:restore
#使用该命令在111.4进行恢复,有询问时输入yes即可
[root@lab ~]# gitlab-ctl start
#重新开启
五.总结
- 不满意太多了,但是似乎总是觉得自己没有精力去将它修改的好一点
GitLab初识以及代码迁移的更多相关文章
- Gitlab来做代码review
Gitlab来做代码review 代码review是代码质量保障的手段之一,同时开发成员之间代码review也是一种技术交流的方式,虽然会占用一些时间,但对团队而言,总体是个利大于弊的事情.如何借助现 ...
- Jenkins教程(七)实现 GitLab 提交/合并代码触发构建
楔子 最近公司推行统一构建平台(基于 Jenkins + Kubernetes 插件创建 slave),原来部门自建的 Jenkins 不让用了. 迁移上统一构建平台的最大阻力是前端模块发布的问题: ...
- EF CodeFirs 代码迁移、数据迁移
最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精 标题叫EF CodeFirs 代码迁移.数据迁移. ...
- [chrome插件分享] gitlab-tree 更方便的浏览Gitlab上的代码
说明 经常玩Github的人肯定都知道大名鼎鼎的octotree吧,这款chrome插件可以说是浏览代码的神器,利用左侧的树形菜单可以很方便的打开目录.浏览文件等,加上Github全站本身使用了pja ...
- Python3中的新特性(3)——代码迁移与2to3
1.将代码移植到Python2.6 建议任何要将代码移植到Python3的用户首先将代码移植到Python2.6.Python2.6不仅与Python2.5向后兼容,而且支持Python3中的部分新特 ...
- 将 Objective-C 代码迁移到 Swift(Swift 2.0更新)-b
本节内容包括: 为你的Objective-c代码做好迁移准备 (Preparing Your Objective-C Code for Migration) 迁移过程(The Migration Pr ...
- ubuntu下lamp环境配置及将window代码迁移至linux系统
因为最近要用需要去实现项目中的一个功能,比较好的做法就是在http://i.cnblogs.com/EditPosts.aspx?opt=1linux中实现.所以最近就将自己的代码全部迁移到linux ...
- 为什么你需要将代码迁移到ASP.NET Core 2.0?
随着 .NET Core 2.0 的发布,.NET 开源跨平台迎来了新的时代.开发者们可以选择使用命令行.个人喜好的文本编辑器.Visual Studio 2017 15.3 和 Visual Stu ...
- jenkins如何获取gitlab上的代码
如何安装jenkins和gitlab我就不重复了,请自行搜索我的博客 那么,jenkins如何获取gitlab上的代码呢? 具体配置步骤如下 1.在gitlab上配置个人访问令牌.注意事项:姓名那里需 ...
随机推荐
- time zone list
GMT UTC WET WET CET CET MET CET ECT CET EET EET MIT Pacific/Apia HST Pacific/Honolulu AST America/An ...
- 如何让winrar5压缩的文件能用低版本winrar打开
https://jingyan.baidu.com/article/39810a2348ab24b636fda681.html 在压缩文件格式选项处点选[RAR4]选项,即之前版本的winrar支持的 ...
- 正确删除k8s版本jenkins的pod
1.kubectl delete -f jenkins-deployment.yaml 或者先删除pod,再删除对应的depllyment 这两步都要执行否则删除pod不管用 2.删除数据目录下的数据 ...
- 《Netty实战》源码运行及本地环境搭建
1.源码路径: GitHub - zzzvvvxxxd/netty-in-action-cn: Netty In Action 中文版 ,中文唯一正版<Netty实战>的代码清单 下载后 ...
- Django 之验证和授权
一.验证和授权概述 Django有一个内置的授权系统.他用来处理用户.分组.权限以及基于cookie的会话系统.Django的授权系统包括验证和授权两个部分.验证是验证这个用户是否是他声称的人(比如用 ...
- Java创建线程的两种方法
大多数情况,通过实例化一个Thread对象来创建一个线程.Java定义了两种方式: 实现Runnable 接口: 可以继承Thread类. 下面的两小节依次介绍了每一种方式. 实现Runnable接口 ...
- synchrnized 和lock的区别
- phaser三个学生做题目
3个学生一起参加考试,一共有三道题,要求所有学生到齐才能开始考试,全部同学都做完第一题,学生才能继续做第二题,全部学生做完了第二题,才能做第三题,所有学生都做完的第三题,考试才结束 public cl ...
- ABP中的AutoMapper
在我们的业务中经常需要使用到类型之间的映射,特别是在和前端页面进行交互的时候,我们需要定义各种类型的Dto,并且需要需要这些Dto和数据库中的实体进行映射,对于有些大对象而言,需要赋值太多的属性,这样 ...
- linux服务器搭建lnmp php 微擎环境备用
以前的时候装个php环境各种的配置麻烦啊,于是乎我就像搜搜一键安装php环境,果然 lamp 和phpstudy 两个环境软件都支持,最后发现lamp 还合胃口就选择了lamp https://lnm ...