git 强制覆盖远程分支

Git 的 push --force 具有破坏性,因为它无条件地覆盖远程存储库,无论你在本地拥有什么。使用这个命令,可能覆盖团队成员在此期间推送的所有更改。然而,有一个更好的办法,当你需要强制推送,但仍需确保不覆盖其他人的工作时,-force-with-lease 这条指令选项可以帮助到你。

众所周知,git 的 push -force 指令是不推荐被使用的,因为它会破坏其他已经提交到共享库的内容。虽然这不总是完全致命的(如果那些修改的内容仍在某些同事的本地工作域中,那之后他们能被重新合并),但是这样的做法很欠考虑,最糟糕的情况会造成灾难性的损失。这是因为 --force 指令选项迫使分支的头指针指向你个人的修改记录,而忽略了那些其他和你同时进行地更改。

强制推动最常见的原因之一是当我们被迫 rebase 一个分支的时候。为了说明这一点,我们来看一个例子。我们有一个项目,其中有一个功能分支,Alice 和 Bob 要同时在这个分支上工作。他们都 git clone... 了这个仓库,并开始工作。

最初,Alice 完成了她负责的功能,并将其 push 到主仓库。这都没啥问题。

Bob 也完成了他的工作,但在 push 之前,他注意到一些变化已被合并到了 master 分支。想要保持一棵整洁的工作树,他会对主分支执行一个 rebase。当然,当他 push 这个经过 rebase 的分支的时候将被拒绝。然而,Bob 没有意识到 Alice 已经 push 了她的工作。Bob 执行了 push --force 命令。不幸的是,这将清除 Alice 在远程主仓库的所有更改和记录。

这里的问题是,进行强制推送的 Bob 不知道为什么他的 push 会被拒绝,所以他认为这是 rebase 造成的,而不是由于 Alice 的变化。这就是为什么 --force 在同一个分支上协作的时候要杜绝的;并且通过远程主仓库的工作流程,任何分支都可以被共享。

但是 --force 有一个不为众人所知的亲戚,它在一定程度上能防止强制更新操作带来的结构性破坏;它就是 --force-with-lease

--force-with-lease 是用于拒绝更新一个分支,除非该分支达到我们期望的状态。即没有人在上游更新分支内容。 实际上,通过检查上游引用是我们所期望的,因为引用是散列,并将父系链隐含地编码成它们的值。

你可以告诉 --force-with-lease 究竟要检查什么,默认情况下会检查当前的远程引用。这在实践中意味着,当 Alice 更新她的分支并将其推送到远程仓库时,分支的引用指针将被更新。现在,除非 Bob从远程仓库 pull 一下,否则本地对远程仓库的引用将过期。当他使用 --force-with-lease 推送时,git 会检查本地与远程的引用是否对应,并拒绝 Bob 的强制推送。--force-with-lease 有效地只在没有人在上游更新分支内容的时候允许你强制推送。就像是一个带有安全带的 --force。它的一个快速演示可能有助于说明这一点:

Alice 已经对该分支进行了一些更改,并已推送到了远程主仓库。Bob 现在又对远程仓库的 master 分支进行了 rebases 操作:

ssmith$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: Dev commit #1
Applying: Dev commit #2
Applying: Dev commit #3复制代码

rebase 之后,他试图将自己的更改 push 上去,但服务器拒绝了,因为这会覆盖 Alice 的工作:

ssmith$ git push
To /tmp/repo
 ! [rejected]        dev -> dev (fetch first)
error: failed to push some refs to '/tmp/repo'
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.复制代码

但 Bob 认为这是 rebase 操作造成的,并决定强制 push

ssmith$ git push --force
To /tmp/repo
 + f82f59e...c27aff1 dev -> dev (forced update)复制代码

然而,如果他使用了 --force-with-lease,则会得到不同的结果,因为 git 会检查远程分支,发现 从上一次 Bob 使用 fetch 到现在,实际上并没有被更新:

ssmith$ git push -n --force-with-lease
To /tmp/repo
 ! [rejected]        dev -> dev (stale info)
error: failed to push some refs to '/tmp/repo'复制代码

当然,在这有一些关于 git 的注意事项。上面展示的,只有当 Alice 已经将其更改推送到远程存储库时,它才有效。这不是一个严重的问题,但是如果她想修改她提交的东西,那她去 pull 分支时,会被提示合并被更改。

一个更微妙的问题是,我们有方法去骗 git,让 git 认为这个分支没有被修改。在正常使用情况下,最常发生这种现象的情况是,Bob 使用 git fetch 而不是git pull`来更新他的本地副本。fetch将从远程仓库拉出对象和引用,但没有匹配的merge则不会更新工作树。这将使本地仓库看起来已经与远程仓库进行了同步更新,但实际上本地仓库并没有进行更新,并欺骗–force-with-lease` 命令,成功覆盖远程分支,就像下面这个例子:

ssmith$ git push --force-with-lease
To /tmp/repo
 ! [rejected]        dev -> dev (stale info)
error: failed to push some refs to '/tmp/repo'

ssmith$ git fetch
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /tmp/repo
   1a3a03f..d7cda55  dev        -> origin/dev

ssmith$ git push --force-with-lease
Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (9/9), 845 bytes | 0 bytes/s, done.
Total 9 (delta 0), reused 0 (delta 0)
To /tmp/repo
   d7cda55..b57fc84  dev -> dev复制代码

这个问题的最简单的答案就是,简单的说“不要在没有合并的情况下 fetch 远程该分支”(或者更常用的方法是 pull,这个操作包含了前面的两个),但是如果由于某种原因你希望在用 --force-with-lease 进行代码上传之前进行 fetch,那么这有一种比较安全的方法。像 git 那么多的属性一样,引用只是对象的指针,所以我们可以创建我们自己的引用。在这种情况下,我们可以在进行 fetch 之前,为远程仓库引用创建“保存点”的副本。然后,我们可以告诉 --force-with-lease 将此作为引用值,而不是已经更新的远程引用。

为了做到这一点,我们使用 git 的 update-ref 功能来创建一个新的引用,以保存远程仓库在任何 rebasefetch 操作前的状态。这有效地标记了我们开始强制 push 到远程的工作节点。在这里,我们将远程分支 dev 的状态保存到一个名为 dev-pre-rebase 的新引用中:

ssmith$ git update-ref refs/dev-pre-rebase refs/remotes/origin/dev复制代码

这时呢,我们就可以进行 rebasefetch 操作,然后使用保存的 ref 来保护远程仓库,以防有人在工作时做了更改:

ssmith$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: Dev commit #1
Applying: Dev commit #2
Applying: Dev commit #3

ssmith$ git fetch
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /tmp/repo
   2203121..a9a35b3  dev        -> origin/dev

ssmith$ git push --force-with-lease=dev:refs/dev-pre-rebase
To /tmp/repo
 ! [rejected]        dev -> dev (stale info)
error: failed to push some refs to '/tmp/repo'复制代码

我们可以看到 --force-with-lease 对于有时需要进行强制推送的 git 用户来说,是一个很有用的工具。但是,对于 --force 操作的所有风险来说,这并不是万能的,如果不了解它内部的工作及其注意事项,就不应该使用它。

文章来源:https://juejin.cn/post/6844903489970126856

docker容器php镜像安装pdo、pdo_mysql、gd扩展

php镜像提供了docker-php-ext-install快捷方式

在容器中执行以下命令,其他扩展也可使用此命令

#pdo
docker-php-ext-install pdo
#pdo_mysql
docker-php-ext-install pdo_mysql

#gd
docker-php-ext-install gd
---------------------------------------------
报错:configure: error: png.h not found
-------
解决:
apt-get update
apt-get upgrade
apt-get install -y libfreetype6-dev libjpeg62-turbo-dev libmcrypt-dev libpng-dev
---------------------------------------------

GeoIp库,php安装geoip扩展,根据ip获取国家、地区、省市街道位置信息

GeoIP,是一套含IP数据库的软件工具。

Geo根据来访者的IP, 定位该IP所在经纬度、国家/地区、省市、街道等位置信息。

GeoIP有两个版本,一个免费版,一个收费版本。

收费版本的准确率高一些,更新频率也更频繁。

因为GeoIP读取的是本地的二进制IP数据库,所以效率很高,比从APNIC读取再转换高很多

PHP支持通过扩展方式读取GeoIP数据。

本文介绍CentOS和Ubuntu系统的安装和使用方法。

1 安装GeoIP

命令方式安装:

yum install geoip geoip-devel                         # CentOS
apt-get install php5-geoip php5-dev libgeoip-dev      # Ubuntu

或者通过源码方式安装,两者选择其一:

GeoIP安装完成后,IP库文件会安装在这个目录下:/usr/share/GeoIP

2 安装geoip扩展

首先要下载geoip扩展源码,最新版地址:https://pecl.php.net/package/geoip

编译成动态库:

$ wget https://pecl.php.net/get/geoip-1.1.1.tgz
$ tar zxvf geoip-1.1.1.tgz
$ cd geoip-1.1.1
$ /usr/local/php/bin/phpize
$ ./configure --with-php-config=/usr/local/php/bin/php-config
$ make && make install

安装完成后,在/usr/lib64/php/modules/目录下(64位系统)生成geoip.so链接库。

打开php.ini文件,在最后加上:

extension=geoip.so

重启PHP-FPM就可以用了。

如果不想安装扩展,也可以直接用PHP代码加载IP库:https://github.com/maxmind/geoip-api-php

3 PHP中使用

详细用法请参考PHP官网:http://php.net/manual/zh/ref.geoip.php

示例:

<?php

$data = geoip_country_code3_by_name($_SERVER['REMOTE_ADDR']); print_r($data);

输出:

string(3) "CHN"

4 更新IP库

GeoIP默认使用Maxmind提供的IP库,这可以用geoip_database_info()方法看到。

例如我的显示:

GEO-106FREE 20170404 Build 1 Copyright (c) 2017 MaxMind Inc All Rights Reserved

在Maxmind网站上,也提供了GeoIP库自动更新方法:http://dev.maxmind.com/geoip/geoipupdate/

Maxmind提供的IP库会在每个月的第一个星期二更新一次,所以我们在此时间后一天执行更新就能拿到最新的APNIC的IP库了。

首先查看是否有文件:/etc/GeoIP.conf

如果没有,就创建一个,内容:

# The following UserId and LicenseKey are required placeholders:
UserId 999999
LicenseKey 000000000000

# Include one or more of the following ProductIds:
# * GeoLite2-City - GeoLite 2 City
# * GeoLite2-Country - GeoLite2 Country
# * GeoLite-Legacy-IPv6-City - GeoLite Legacy IPv6 City
# * GeoLite-Legacy-IPv6-Country - GeoLite Legacy IPv6 Country
# * 506 - GeoLite Legacy Country
# * 517 - GeoLite Legacy ASN
# * 533 - GeoLite Legacy City
ProductIds GeoLite2-City GeoLite2-Country GeoLite-Legacy-IPv6-City GeoLite-Legacy-IPv6-Country 506 517 533

然后在Linux下手动执行一遍更新命令:

geoipupdate -v

如果没有出错,就完成更新GeoIP库了。

4.1 crontab自动更新IP库

我们可以使用Linux crontab可以实现自动更新IP库。

使用如下命令打开当前用户的crontab文件:

crontab -e

添加一行:

30 2 * * 3#1 /usr/bin/geoipupdate

这一段的功能是,在每个月第一个星期三自动执行 geoipupdate 命令,执行时间在凌晨2点30分。

因为Maxmind是每月的第一个星期二更新IP库,所以我们选择延迟一点,避免时差引起误差。

然后重启 crond:

/sbin/service crond restart

如果有防火墙,geoipupdate需要 DNS 和HTTPS(443)端口打开。

4.2 手动更新IP库

如果用PHP更新,让PHP执行SHELL命令执行更新:

<?php
echo shell_exec('geoipupdate -v');

执行完成会打印出更新的相关信息。

如果不需要输出信息可以去掉-v参数。

文章来源:https://www.awaimai.com/2117.html

linux centos7安装ffmpeg

1:先安装epel-release
yum install epel-release

2:安装nux存储库
rpm -v –import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm

3:安装ffmpeg
yum install ffmpeg ffmpeg-devel

4:测试下
ffmpeg -version

docker学习-常用命令

win10 系统  docker 下载地址:https://hub.docker.com/editions/community/docker-ce-desktop-windows/

1.docker images
列出所有镜像

2.docker ps
列出正在运行中的镜像
-a
列出所有镜像

3.docker pull images_name
拉取名称为 images_name 的镜像
可通过 docker search images_name 来搜索镜像

4.docker run

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
  -a, --attach=[]            登录容器(以docker run -d启动的容器)
  -d, --detach=false         指定容器运行于前台还是后台 
  -i, --interactive=false    打开STDIN,用于控制台交互
  --name=""                  指定容器名字,后续可以通过名字进行容器管理,links特性需要使用名字
  --net="bridge"             容器网络设置
  -P, xxx:nnn                指定映射的端口,容器中的程序监听nnn,映射到主机的xxx,此时访问主机的xxx端口会进入容器中监听nnn端口的程序
  -t, --tty=false            分配tty设备,该可以支持终端登录
  -u, --user=""              指定容器的用户
  -v, --volume=[]            给容器挂载存储卷,挂载到容器的某个目录
  -w, --workdir=""           指定容器的工作目录

命令示例:docker run -it -p 80:8133 –name=”my-work” -v C:\www:/app/www -v C:\nginx:/app/nginx  IMAGE_ID  /bin/bash
示例简介:新建一个容器去跑名称为 nginx 的镜像,将主机的80端口指向容器的8133端口,为容器起名为 my-work ,使用镜像 id 为 IMAGE_ID 的镜像,挂在了两个目录
i:打开容器的标准输入。
t:告诉docker为容器建立一个命令行终端。
/bin/bash:告诉docker要在容器里面执行此命令。

5.docker cp
在容器和主机之间复制文件
命令示例:docker cp CONTAINER_ID://etc/nginx/conf.d/default.conf  D:\myfile\default.conf
命令简介:将容器id为 CONTAINER_ID 的指定路径下的文件复制为到主机的指定目录下(文件已存在会被直接覆盖)

6.docker exec

docker exec [OPTIONS] IMAGE [COMMAND] [ARG...]
  -d, 分离模式: 在后台运行 
  -i, 即使没有附加也保持STDIN 打开,用于控制台交互
  -t, 分配一个伪终端

命令示例1:
docker exec -it CONTAINER_ID /bin/sh /home/uname/test.sh
示例简介:在容器 CONTAINER_ID 中以交互模式执行容器内 /home/uname/test.sh 脚本

命令示例2:
docker exec -itd CONTAINER_ID /bin/bash
示例简介:在容器 CONTAINER_ID 中开启一个交互模式的终端

7.docker commit
容器备份
命令示例:docker  commit  -p CONTAINER_ID  new_images_name
命令简介:将 CONTAINER_ID 备份为名称为 new_images_name 的镜像,-p表示 commit 时暂停容器

8.docker save
将指定镜像保存成 tar 归档文件
命令示例:docker save -o D:\myfile\new_images_name.tar nginx
命令简介:将镜像名称为nginx的镜像文件打包成new_images_name.tar 存放在D:\myfile\ 文件夹下

9.docker load
导入使用 docker save 命令导出的镜像。
命令示例:docker load -i D:\myfile\new_images_name.tar

10.docker start|restart|stop CONTAINER_ID
容器 启动|重启|停止

11.docker inspect
获取容器信息
命令示例:docker inspect CONTAINER_ID | grep “IPAddress”
命令简介:获取容器ip,(ip可用于容器间网络通信)

12.docker rm
删除容器
命令示例:docker rm CONTAINER_ID

13.docker rmi
删除镜像
命令示例:docker rmi IMAGE_ID

Linux 用户必须知道的 14 个常用 Linux 终端快捷键

你知道什么把专业用户和普通用户分开的吗?掌握键盘快捷键。以下是一些每个 Linux 用户必须使用的键盘快捷键。 使用命令行时,这些 Linux 快捷键将提升你的工作效率和效率。

1. Tab

这是你不能没有的 Linux 快捷键。它将节省你 Linux 命令行中的大量时间。

只需要输入一个命令,文件名,目录名甚至是命令选项的开头,并敲击 tab 键。 它将自动完成你输入的内容,或为你显示全部可能的结果。

如果你只记一个快捷键,这将是必选的一个。

2. Ctrl + C

这些是为了在终端上中断命令或进程该按的键。它将立刻终止运行的程序。

如果你想要停止使用一个正在后台运行的程序,只需按下这对组合键。

3. Ctrl + Z

该快捷键将正在运行的程序送到后台。 通常,你可以在使用 & 选项运行程序前之完成该操作, 但是如果你忘记使用选项运行程序,就使用这对组合键。

4. Ctrl + D

这对键盘快捷键将使你退出当前终端。如果你使用 SSH 连接,它将会关闭。 如果你直接使用一个终端,该应用将会立刻关闭。

把它当成“退出”命令。

5. Ctrl + L

你怎么清空你的终端屏幕?我猜是用 clear 命令。

你可以使用 Ctrl+L 清空终端,代替输入 C-L-E-A-R。得心应手,不是吗?

6. Ctrl + A

该快捷键将移动光标到所在行首。

假设你在终端输入了一个很长的命令或路径,并且你想要回到它的开头, 使用方向键移动光标将花费大量时间。注意你无法使用鼠标移动光标到行首。

这是 Ctrl+A 节省时间的地方。

7. Ctrl + E

这对快捷键与 Ctrl+A 相反。 Ctrl+A 送光标到行首,反之 Ctrl+E 移动光标到行尾。

8. Ctrl + U

输入了错误的命令? 代替用退格键来丢弃当前命令,使用 Linux 终端中的 Ctrl+U 快捷键。 该快捷键会擦除从当前光标位置到行首的全部内容。

9. Ctrl + K

这对和 Ctrl+U 快捷键有点像。 唯一的不同在于不是行首,它擦除的是从当前光标位置到行尾的全部内容。

10. Ctrl + W

你刚才了解了擦除到行首和行尾的文本。 但如果你只需要删除一个单词呢?使用 Ctrl+W 快捷键。

使用 Ctrl+W 快捷键,你可以擦除光标位置前的单词。 如果光标在一个单词本身上,它将擦除从光标位置到词首的全部字母。

最好的方法是用它移动光标到要删除单词后的一个空格上, 然后使用 Ctrl+W 键盘快捷键。

11. Ctrl + Y

这将粘贴使用 Ctrl+W,Ctrl+U 和 Ctrl+K 快捷键擦除的文本。 如果你删除了错误的文本或需要在某处使用已擦除的文本,这将派上用场。

12. Ctrl + P

你可以使用该快捷键来查看上一个命令。 你可以反复按该键来返回到历史命令。 在很多终端里,使用 PgUp 键来实现相同的功能。

13. Ctrl + N

你可以结合 Ctrl+P 使用该快捷键。Ctrl+N 显示下一个命令。 如果使用 Ctrl+P 查看上一条命令,你可以使用 Ctrl+N 来回导航。 许多终端都把此快捷键映射到 PgDn 键。

14. Ctrl + R

你可以使用该快捷键来搜索历史命令。

文章来源:https://www.sohu.com/a/258533313_495675