如何解决Merge主分支代码导致本地代码被删除?

背景

之前需求发布的时候,把代码发布到了预发布分支上,但是产品突然发现一个体验问题阻塞了发布,需要先revert掉,等改动完成后再继续发布。

现状

改动完成后,需要同步一下主分支上的代码,在本地解决冲突后再合入主分支。此时会发现Merged后将会把本地代码给删掉。

复盘定位

如图所示,其实问题的根源就是:主分支上的revert没有被撤销,导致合入开发分支的时候本地代码都被revert掉了。

解决办法

简而言之就是,撤销之前的主分支上的revert就可以让主分支上的代码合入到开发分支上又不会把本地代码删掉。相当于告诉git,主分支上这批代码不用被删掉了。具体步骤如下:

  1. 从最新的主分支上创建一个临时分支
  2. 切换到这个临时分支
  3. 在临时分支上revert(撤销)掉之前的revert提交
  4. 将临时分支合入到开发分支上,同步最新主分支代码
  5. 解决问题

如何办理香港银行卡?

背景

最近解禁了一些股票,想着等价格合适就兑现离场了。研究了一下流程才知道,美股是没办法直接兑现的,只能依靠香港做一个跳板,先把股票卖出得到美元,再转成港元出金到香港银行卡里,最后再转钱回大陆。

出入金流程

由于22年入职的缘故,当时大陆是允许本人在大陆注册富途牛牛的账户。因此,在有港卡前。我其实已经有了卷商的美股账户、卷商的港股账户,由于这个缘故也让我的出金复杂度有所降低。入职这个时间点的我,其实只要再办理一张香港银行卡就可以顺利出金了。

选择什么港卡?

不得不说小红书真的是一个好东西,有很多经验都能在上面找到。办理港卡的经验也不例外,我也是在上面了解到的香港各个银行之前的区别才做出的选择。

目前本人是在深圳工作+粤语沟通无障碍(其实业务员都会说国语,语言不会是问题)+较熟悉香港,所以亲自前往香港办事的难度不高且成本较低(签注一次15元)。综合安全性、成本、便利性等原因后选择了中银香港作为我的香港开户行。

如何预约中银香港?

1.访问“BOCHK”官网

預約開立香港賬戶 | 聯絡我們 | 中銀香港

2. 选择“中国公民身份证”和“一般账户”后,勾选同意协议,点击“继续”

3.然后就是填写一些个人资料预约时间即可

4.填写好资料点击提交就能预约成功了

吐槽

不得不说香港银行的信息化水平真的是落后大陆至少10年了,因为工作日需要工作缘故,我预约银行的时候都只能选择周六,但选择时候后总是得一个个选,然后点“选择分行”才知道当日该时段是否可以预约,效率真的是低的可怕!因此我这里可以分享一个我编写的数据分析脚本,希望可以帮大家更方便找到可以约的银行。

脚本

(function() {
    'use strict';
    const isDev = true; // 开发者模式(是否展示URL)
    const onlyShowCanBook = true; // 仅展示可以预约的银行

    function OpenTimeTable(date, time, district, count) {
        this.date = date;
        this.time = time;
        this.district = district;
        this.count = count;
    }

    const url = '/whk/form/openAccount/jsonAvailableBrsByDT.action';
    const district = [];
    const districtName = [];
    const timeTables = [];
    timeTables.push(new OpenTimeTable("日期📅", "时间段⌚️", "区🗺️", "数量⏱️"))
    Object.values($("select[name='bean.district']").children()).forEach((item) => {
        if (/^_/.test(item.value)) {
            district.push(item.value);
            districtName.push(item.label);
        }
    })

    const appDate = $("input[name='bean.appDate']")[0].value;
    const appTimeChildren = $("select[name='bean.appTime']").children();
    const appTimeLimit = appTimeChildren.length;
    const appTimeNames = [];

    Object.values($("select[name='bean.appTime']").children()).forEach((item)=>{
        if(item.localName === "option" && item.value !== ""){
            appTimeNames.push(item.label);
        }
    })

    if (appDate !== "") {
        let total = (appTimeLimit - 1) * district.length;
        for (let i = 1; i < appTimeLimit; i++) {
            const appTime = "P0" + i;
            const appTimeName = appTimeNames[i-1] || "未知"
            district.forEach((item, index) => {
                $.ajax({
                    type: "POST",
                    dataType: "json",
                    url: url,
                    data: "bean.appDate=" + appDate + "&bean.appTime=" + appTime + "&bean.district=" + item + "&bean.precondition=D",
                    success: (res) => {
                        isDev && console.info("success>>", "bean.appDate=" + appDate + "&bean.appTime=" + appTime + "&bean.district=" + item + "&bean.precondition=D");
                        if (onlyShowCanBook && res.length - 1 === 0) {
                            total--;
                            return;
                        }
                        timeTables.push(new OpenTimeTable(appDate, appTimeNames[i-1], districtName[index], res.length - 1));
                    },
                    fail: () => {
                        isDev && console.info("fail>>", "bean.appDate=" + appDate + "&bean.appTime=" + appTime + "&bean.district=" + item + "&bean.precondition=D");
                        if (onlyShowCanBook) {
                            total--;
                            return;
                        }
                        timeTables.push(new OpenTimeTable(appDate, appTimeNames[i-1], districtName[index], -1));
                    },
                });
            })
        }
        const intervalId = setInterval(() => {
            isDev && console.log(timeTables.length, total);
            // 需要将表头减掉
            if (timeTables.length - 1 === total) {
                console.table(timeTables);
                clearInterval(intervalId);
            }
        }, 3000);
    }

})();

使用指南

此处以Firefox为例,Chrome应该是类似的。

  1. 在网页的“预约日期”字段选择想要查询的日期
  2. 打开F12
  3. 将代码粘贴到“1”处
  4. 在“2”处选择代码运行的页面层级为“预约开立香港账户”
  5. 点击“3”处的“运行”按钮
  6. 等待代码执行后,会在“4”处展示之前选择的日期下,可以预约的银行位置与时间段
  7. 结合下面这张区域划分图和自己的行程安排预约就行

行动攻略

材料

  • 通行证
  • 过关小票
  • 身份证
  • 信用卡账单
  • 工卡
  • 在职证明
  • 股票授予合同(电子)
  • 10,000HKD 现金(可以找银行换汇/香港按ATM)

过关

07:30 起床

08:00 出门

09:00 到达福田口岸

09:15 到达香港

09:20 落马洲上车

10:30 到达长沙湾

10:45 到达李郑屋邨分行

开户

  1. 进门直接跟保安说明要开户
  2. 被带到人工柜台
  3. 营业员确认预约时间并且发放号码小票
  4. 营业员表示可以自己先通过BOCHK的APP进行资料预填写
  5. 填写完一直等到11:15,另外一名营业员过来接待
  6. 出示身份证、通行证和过关小票
  7. 开始问开户理由(15分钟)
    1. 表示用来作公司股票分红出金用
    2. 要求证明资金来源,出示电子授予合同
    3. 要求证明公司身份,出示工卡
    4. 要求证明居住地,出示流水账单、
  8. 拟定合同,开港元储蓄账户(已经有卷商的投资账户了,就没必要开中银的了,我这个也只是作跳板用,需求不高)
  9. 主管审核
  10. 港元账户开户完成
  11. 教授如何使用手机银行+如何使用BOC Pay(港版云闪付)
  12. 出门激活账户

激活账户

营业员明确表示需要当日存款10,000HKD激活账户。如果像我一样没有预先准备这么多的现金,可以直接到带有”银联”标志的ATM机取款,汇率跟银联的实时汇率。中银的取款机单次取款有4,000HKD的限制,所以需要插三次卡,取三次才够钱。

取完钱后,去隔壁存款机上把钱存到卡里即可激活账户,只要保证在手机银行里能看到结余有10,000HKD就行。其实这个钱也不用给营业员看,我猜测这里应该是会有风控限制,要求至少存10,000HKD才行。不过我也无所谓,优先解决了港卡问题就行。

投资账户

当日无法直接开设投资账户,找营业员了解后得知需要有特定的营业员才能开,但当日人家休假了,所以没办法直接开。后面如果有了一定流水后可以尝试在手机银行上开启,但如果触发了风控就还是需要本人到香港才能办理投资账户。这里我的需求其实没有,因为之前富途牛牛已经有投资账户了,我直接用富途牛牛的就好了。

卡片邮寄

现场是没办法将卡片改成使用快递邮寄的,只能使用平邮等一个月才能寄回大陆,我不急着用卡就还好,即使后面寄丢了,我看别人分享也可以要求银行重新寄件解决,问题不大。

补充

果不其然,银行卡平邮还是寄丢了(即使留了信箱地址,但银行只给写到XX省XX市XX路,连门牌号都不写,能寄得到就有鬼了)。最后还是花了100港币,找银行寄DHL才收到实体卡。另外补卡是需要锁定卡的,锁定之后需要肉身下香港,在ATM上办理一次业务才能解锁(插卡到ATM里查一次余额也可以),会很麻烦,尽量第一次弄的时候就让银行帮你寄快递就好了,别省那点钱了。

总结

总共花费了1个小时才开完账户,效率实在是太低了,而且周六银行13点就关门,其实办完我这个开户后,营业员就准备下班了,想再办一家已无可能。另外办卡前的审核贼严格,跟审问犯人一样,好在对港资银行有点概念,肯定屁事贼多,带齐了所有材料,不然真的有可能白跑一趟。不过最后解决了问题就行,我也就安心了。