2018年12月25日 星期二

[點網] .NET 的擴充方法

.NET 的 擴充方法 (C#/VB.NET)

https://docs.microsoft.com/zh-tw/dotnet/visual-basic/programming-guide/language-features/procedures/extension-methods

https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/classes-and-structs/extension-methods

不用繼承,也不用改變原始程式的情況下,替類別新增新的方法。

## VB .NET
要 Imports System.Runtime.CompilerServices 。
要在 Module 宣告。若要給 dll 外部使用,Module 要宣告 Public。
要擴充的方法上面要加上 <Extension()>,該方法或函式的第一個參數就是要擴充的型別。
可擴充的型別有:
  類別 (參考類型)
  結構 (實值類型)
  介面
  委派
  ByRef 和 ByVal 引數
  泛型方法的參數
  陣列

## C#
要定義在 static 物件中的 static 方法。
方法的第一個參數要加上 this 型別。
擴充方法是定義成靜態方法,但透過執行個體方法語法呼叫。

2018年12月24日 星期一

[心得]幾種 系統內溝通 的方式

幾種 系統內溝通 的方式

用 ros 的名詞:topic, service, actionlib

1. topic 方式,有兩個習慣模式
  eventbus: event listen/event raise
  topic: publish/subscribe
  兩者極為相似,也常常被當成一樣的東西。依我的定義,其中不同的地方是:
  topic 在系統中,幾乎只有單程,沒有去與回的對應。接收方不需要與發送方互動時使用。也可不理會重覆傳送的問題。
  eventbus 在系統中,有可能會存在著事件去與回的處理,每次事件會在乎重覆傳送的判定問題。
  但因為這兩種也都可以用簡單程式方式解決掉彼此的差異,所以視為一樣也沒有什麼問題。
2. service 方式
  也就是 http 採用的模式,也就是 request/response。必定由 client 發起 request,由 server 送回 response。

3. actionlib 方式
  由 client 設定 goal,server 定期或定時回報 progress ,當最後結束的時候回傳 result 的模式。在進行的過程中,還可以 cancel 中斷執行以及查看 status。
  這種模式也可由前兩種組合, request/response + event 來做到。流程稍有不同。
  client 送出 request,server 回應 response 是否執行,然後由 server 發送 event 來通知 client 進度與結果。

2018年10月5日 星期五

[點網核] win2003, win7 與 .net core 不是很熟的樣子

.net core 搞半天,win2003 不認得它……

win7 也跟它不熟……

如果是抱怨 hostfxr.dll 無法載入,那就安裝以下更新

https://www.microsoft.com/en-us/download/details.aspx?id=26764
KB2533623

2018年9月25日 星期二

[點網][超速譯]VS2017 的中斷點

https://blogs.msdn.microsoft.com/visualstudio/2018/09/13/how-can-i-pause-my-code-in-visual-studio-breakpoints-faq/

Visual Studio 是我用過最好用的 IDE,沒有之一。
中斷點這件事也是我看過不少碼農不甚使用的事。正好有官方提出一些小技巧給大家知道。
快速摘譯重點,成為超速譯的一篇。


設立 breakpoint

(1)左點左邊界 或是 按F9
(2)按F5

管理 breakpoint

(1)breakpoint window
(2) Debug -> Window -> Breakpoints

Conditional Breakpoint

(1)設定 breakpoint
(2)鼠標飄到 breakpoint 上,按下齒輪圖示
(3)選擇 Conditions,然後設定條件
(4)條件輸入完畢,關閉設定窗

Iteration breakpoint

(1)設定 breakpoint
(2)鼠標飄到 breakpoint 上,按下齒輪圖示
(3)選擇 Conditions,然後設定條件為 Hit Count


Function breakpoint

(1) Debug -> New Breakpoint -> Break at Function


Value change breakpoint

* C++, data breakpoints
* Watch Window or the Breakpoints Window 右點 變數 選擇 Break when value changes
* managed code, 針對某個 instance 的屬性偵測改變
(1)在 break mode,右點物件選擇 Make Object ID
(2)在欲偵測的屬性 setter 加入一個 conditional breakpoint 條件是 this == $1
(3)按F5,會停在 setter
(4)在 Call Stack 雙點前一個 frame 可以看到改變屬性的 code 是哪一行


exception breakpoint

在 Exception Settings 窗,設定哪些 exception 要停下來


call stack breakpoint

(1)Debug -> Windows -> Call Statck
(2)右點 calling function,選擇 Breakpoint -> Insert Breakpoint


disassembly breakpoint

(1)打開 disassembly window, Debug -> Windows -> Disassembly
(2)左點左邊界或按F9

2018年9月13日 星期四

[python] WARNING:tornado.general:Invalid multipart/form-data

用 flask 自帶的 server,有時就是會發出 500 之後就無法動作,要重開一次。
想說試試用 tornado 來裝 flask。結果就發現一個 warning。

WARNING:tornado.general:Invalid multipart/form-data
查了一下,找到 tornado 原始碼 http://www.tornadoweb.org/en/stable/_modules/tornado/httputil.html,發現應該是 Content-Disposition 只要不是 form-data 就叫。
於是再找一下定義 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition

> Only the value form-data, as well as the optional directive name and filename, can be used in the HTTP context.
attachment 只能用在非 http 的情況。好吧,應該是要改成 form-data 才合規定。就改吧

## 同場加映
header 裡的的資料若是超過 ISO-8859-1 還是有救。
剛好在 Content-Disposition 定義找到
https://tools.ietf.org/html/rfc5987
ex: foo: bar; title*=UTF-8''%c2%a3%20and%20%e2%82%ac%20rates

## tornado 原始碼部份
def parse_multipart_form_data(boundary, data, arguments, files):
    """Parses a ``multipart/form-data`` body.

    The ``boundary`` and ``data`` parameters are both byte strings.
    The dictionaries given in the arguments and files parameters
    will be updated with the contents of the body.

    .. versionchanged:: 5.1

       Now recognizes non-ASCII filenames in RFC 2231/5987
       (``filename*=``) format.
    """
    # The standard allows for the boundary to be quoted in the header,
    # although it's rare (it happens at least for google app engine
    # xmpp).  I think we're also supposed to handle backslash-escapes
    # here but I'll save that until we see a client that uses them
    # in the wild.
    if boundary.startswith(b'"') and boundary.endswith(b'"'):
        boundary = boundary[1:-1]
    final_boundary_index = data.rfind(b"--" + boundary + b"--")
    if final_boundary_index == -1:
        gen_log.warning("Invalid multipart/form-data: no final boundary")
        return
    parts = data[:final_boundary_index].split(b"--" + boundary + b"\r\n")
    for part in parts:
        if not part:
            continue
        eoh = part.find(b"\r\n\r\n")
        if eoh == -1:
            gen_log.warning("multipart/form-data missing headers")
            continue
        headers = HTTPHeaders.parse(part[:eoh].decode("utf-8"))
        disp_header = headers.get("Content-Disposition", "")
        disposition, disp_params = _parse_header(disp_header)
        if disposition != "form-data" or not part.endswith(b"\r\n"):
            gen_log.warning("Invalid multipart/form-data")
            continue
        value = part[eoh + 4:-2]
        if not disp_params.get("name"):
            gen_log.warning("multipart/form-data value missing name")
            continue
        name = disp_params["name"]
        if disp_params.get("filename"):
            ctype = headers.get("Content-Type", "application/unknown")
            files.setdefault(name, []).append(HTTPFile(  # type: ignore
                filename=disp_params["filename"], body=value,
                content_type=ctype))
        else:
            arguments.setdefault(name, []).append(value)


2018年9月12日 星期三

[點網] process.MainWindowHandle == 0


## 原因
為了拿到 process 的 MainWindowHandle 作隱藏/顯示。
但是在隱藏之後,process 的 MainWindowHandle 會等於 0


## 使用 AttachConsole GetConsoleWindow FreeConsole
其中一個方法是針對 console app 的作法是接到 console,拿到其 consolewindow 要到 ID,再離開。
使用 AttachConsole GetConsoleWindow FreeConsole

宣告需要:
```
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AttachConsole(uint dwProcessId);
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool FreeConsole();
int GetSmsdMainWindowHandle(int procID)
    Int32 tryHandle = 0;
    try
    {
        AttachConsole((uint)procID);
        tryHandle = GetConsoleWindow().ToInt32();
        FreeConsole();
    }
    catch (Exception)
    {
        //pass
    }
    finally
    {
        FreeConsole();
    }
    return tryHandle;
}
```

使用方法:
```
int smsdMainWindowHandle = GetSmsdMainWindowHandle(xProc.Id);
```


## 使用 EnumChildWindows GetWindowThreadProcessId
另一個方法是列舉所有 子window 再拿到其 window thread 的 process ID。
使用 EnumChildWindows GetWindowThreadProcessId

宣告需要:
```
private struct SearchData
{
    // You can put any vars in here...         
    public int currentTaskID;
    public IntPtr currenthWnd;
}
private delegate bool EnumWindowsProc(IntPtr hWnd, ref SearchData data);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, ref SearchData data);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int ProcessId);
bool EnumProc(IntPtr hWnd, ref SearchData data)
{
    int lProcID;
    GetWindowThreadProcessId(hWnd,out lProcID);
    if (lProcID == data.currentTaskID)
    {
        data.currenthWnd = hWnd;
    }
    return true;
}
```

使用方法:
```
SearchData n = new SearchData();
n.currentTaskID = xProc.Id;
EnumChildWindows(IntPtr.Zero,new EnumWindowsProc(EnumProc),ref n);
int smsdMainWindowHandle = (int)n.currenthWnd;
```

這個方法的 VB Code 由 Cyrus 提供:
```
Dim currenthWnd = 0
Public Function fEnumWindowsCallback(ByVal hWnd As Integer, ByVal lpData As Integer) As Integer
    fEnumWindowsCallback = 1
    Dim lProcID As Integer
    Call GetWindowThreadProcessId(hWnd, lProcID)
    If lProcID = currentTaskID Then
        currenthWnd = hWnd
    End If
End Function

Call EnumChildWindows(0&, AddressOf fEnumWindowsCallback, 0&)
If currenthWnd <> 0 Then
    If goSECSInterface.GEMObject.HideSMSD = True Then
        ShowWindow(currenthWnd, SW_HIDE)
    Else
        ShowWindow(currenthWnd, SW_NORMAL)
    End If
End If
```

## 參考:

  • * https://stackoverflow.com/questions/8949652/do-windows-api-enumwindows-and-enumchildwindows-functions-behave-differently-in

2018年9月11日 星期二

[pi-nas]raspberry pi glusterfs 換硬碟

在樹莓派上裝 gluster,硬碟壞了要換掉。查了幾種方式要來試試。但是想先試個最無腦的方法,就是 umount 舊硬碟,mount 新硬碟,看看有沒有比較方便。以下就是過程。

步驟 1
停止 gluster daemon
`sudo systemctl stop glusterfs-server`
這個只能讓 umount /mnt/gv0 成功,umount /data/brick1 還是不行
glusterfsd 還是佔著,查詢誰在用檔案或掛載 `fuser -m -u /data/brick1`。
用 `sudo /etc/init.d/glusterfs-server stop` https://gluster.readthedocs.io/en/latest/Administrator%20Guide/Start%20Stop%20Daemon/ 也不行
最後只好使用 `kill -9 PID` 處理掉,比較溫和應該用 `kill -15 PID`
umount /data/brick1 成功

步驟 2
拔掉舊的硬碟,插入新的硬碟,格式化
`sudo mkfs.xfs -i size=512 /dev/sda1`

修改 fstab `PARTUUID=c121432b-52f5-4bb2-a260-0d38992df858 /data/brick1 xfs defaults 1 2` 其中 PARTUUID 用 `blkid /dev/sda1` 查詢

`sudo mount -a`

`sudo mkdir /data/brick1/gv0`

到這,試試重開。

步驟 3
檢查 heal 狀況 `sudo gluster volume heal gv0 info`

```
pi@pi315:~ $ sudo gluster volume heal gv0 info
Brick pi314:/data/brick1/gv0
Status: Connected
Number of entries: 0
Brick pi315:/data/brick1/gv0
Status: Transport endpoint is not connected
Number of entries: -
```

看來直換是沒有,還需要下些指令。glusterfsd 3.9.0 有 reset-brick 看起來很好用,但!
我的 glusterfsd 是 3.8.8-1 沒有支援 reset-brick。
自身 replace `sudo gluster volume replace-brick gv0 pi315:/data/brick1/gv0 pi315:/data/brick1/gv0 commit force` 也不行。
所以一定要換個新名字,所以改成 gv0_1:
`sudo gluster volume replace-brick gv0 pi315:/data/brick1/gv0 pi315:/data/brick1/gv0_1 commit force`

這個時候,pi315 的 glusterfsd 才起得來

```
pi@pi314:~ $ sudo gluster volume status
Status of volume: gv0
Gluster process                             TCP Port  RDMA Port  Online  Pid
------------------------------------------------------------------------------
Brick pi314:/data/brick1/gv0                49153     0          Y       1492
Brick pi315:/data/brick1/gv0_1              49153     0          Y       1846
Self-heal Daemon on localhost               N/A       N/A        Y       26710
Self-heal Daemon on pi315                   N/A       N/A        Y       1851
Task Status of Volume gv0
------------------------------------------------------------------------------
There are no active volume tasks
```


然後,heal 就自動開始了。
查看 heal 狀態 `sudo gluster volume heal gv0 info`

到這其實就結束了,但是如果很在意那個 gv0_1 的話,我在 heal 結束之後又執行了一次 `replace-brick` 只是把 gv0_1 又換成 gv0。要考慮硬碟空間要足夠兩倍大。看硬碟閃,還是從 pi314 那裡拿資料。

參考:
## 有故意使用 setfattr 強迫 heal
https://serverfault.com/questions/710220/how-do-you-add-a-replacement-hdd-to-a-glusterfs-volume
https://lists.gluster.org/pipermail/gluster-users/2014-August/018515.html
https://docs.gluster.org/en/v3/Administrator%20Guide/Managing%20Volumes/#replace-brick

## 只使用 sudo gluster volume replace-brick 舊brick 新brick
https://sysadmins.co.za/replace-faulty-bricks-in-glusterfs/

## 使用 reset-brick
https://docs.gluster.org/en/latest/release-notes/3.9.0/

2018年8月29日 星期三

[pi-nas] raspbain 樹莓派 wlan0 失效,自動重啟

wlan0 失效,自動重啟,這個網路上有找到一些解法,但是有些太舊方法已經失效。於是這次重做一次,再記錄下來。

總體的概念是,使用 bash script,每隔一段時間測試網路狀況,如果有問題就重啟。


  •     測試的方法是用 curl 向 google 與 yahoo 要網頁,有回應就算成功。
  •     重啟的動作,ifup/ifdown,ifconfig wlan0 up/down 或是 dhcpcd restart 都無用。ifup/ifdown 在 raspbian 有問題,找不到 wlan0,而後兩個失敗的原因是 route default gateway 的設定會失蹤。解決方法直覺的是使用 `sudo route add default gw 192.168.1.1`,另一個則是在 dhcpcd restart 之前做 `sudo ip addr flush dev wlan0`,而我選擇後者。
  •     每隔一段時間執行的動作是使用 cron,在 raspbian 這個版本用的是 anacron,直接在 /etc/crontab 加入設定即可。它自己就會檢查與執行,不用重啟 cron deamon。

 
完整    bash script 如下:
    ```
    #!/bin/bash
    urls=("http://www.google.com" "http://tw.yahoo.com")
    http_code_accept=("200" "301" "302" "404")
    count=${#urls[@]}
    connected=0

    echo "now start to check net is on or not"
    echo "bash file in /home/pi/net_restart.sh"
    #check net is connected or not
    for ((i=0;i<$count;i++))
    do
        url=${urls[$i]}    
        result=$(curl -o /dev/null -s -m 10 -w "%{http_code}" "$url")
        for flag in ${http_code_accept[@]}
        do
            #echo $flag $result $url
            if [ $flag = $result ]; then            
                connected=$(expr $connected + 1)
                echo "accept" $url $connected
            fi
        done
    done

    if [ $connected -eq 0 ]; then
        echo "network not good"
        echo "going to restart network"
        ip addr flush dev wlan0
        systemctl restart dhcpcd
    fi
    ```

2018年8月9日 星期四

[點網]現在 visual studio 正在轉型中

最近研究 roslyn 發現幾個點。


  • 2013 還是使用 native 的 csc.exe vbc.exe。而 2015 2017 開始,使用 roslyn 做為 compiler。
  • vs extension 的規格開始改變,名字叫做 .net standard,所以 NuGet 有的東西的打包沒有跟上的話,在 2015 之後就會裝不進舊的 vs。當然也會有舊的東西裝不進新的 vs。像是 .Net Compiler Platform SDK 如果用 extension (NuGet or VSIX)裝的話,會被 vs2017 關掉。要從 Visual Studio Installer 的 Individual components 頁籤安裝才行。現在是混亂期,從 2015 到現在已經三年了吧。
  • 現在除了 library 打包換規格之外,現在也因為推出 .Net Core 的關係,framework 也是混亂期,library 有新舊兩種的 portable 格式,給 framework 用的與 core 用的也是要慎選。

2013 與 2017 的間隙很大,應該是沒辦法直跳,2015 應該要保留著用來轉換專案用。
就跟 2005 一樣,用來轉換 2003 與 2008 的專案。

現在如果要專案升級最好還是等等。

相關連結:
https://www.facebook.com/groups/DotNetUserGroupTaiwan/permalink/1945828905710218/

[點網]實際的四捨四入

文章連結:https://www.facebook.com/groups/DotNetUserGroupTaiwan/permalink/1945395752420200/

一定要筆記

今天在使用某個成績系統時候遇到四捨五入結果與Excel的ROUND()比對有誤差的問題

與負責的工程師一起測了一下之後

發現造成此問題的原因是因為 .net 中 Math.Round() 函數的行為

於是來與各位分享一下

大家先猜猜下面四捨五入到小數第二位的輸出結果

Math.Round(18.265, 2);

Math.Round(18.265, 2, MidpointRounding.AwayFromZero);

Math.Round(18.275, 2);

Math.Round(18.275, 2, MidpointRounding.AwayFromZero);

Math.Round(18.275M, 2);

Math.Round(18.275M, 2, MidpointRounding.AwayFromZero);

================================

.

.

答案分別是

Math.Round(18.265, 2) = 18.26

Math.Round(18.265, 2, AFZ) = 18.27

Math.Round(18.275, 2) = 18.27

Math.Round(18.275, 2, AFZ) = 18.27

Math.Round(18.275M, 2) = 18.28

Math.Round(18.275M, 2, AFZ) = 18.28

而造成此原因是因Math.Round() 在遇到5的時候

預設是使用 MidpointRounding.ToEven 作為捨去或進位的依據

也就是會round到該位最近的偶數

假設我需要四捨五入到小數第二位

在遇到18.265的時候因為6是偶數,所以會做捨去

如果18.265使用了MidpointRounding.AwayFromZero就會不管奇偶去做四捨五入

得到與Excel的ROUND()相同的18.27

但又有一個問題

18.275出來為何都是18.27?

這是因為在四捨五入過程中遇到了精度丟失

造成了非預期的四捨五入行為

改為decimal之後就正常了

【結論】

處理小數四捨五入的邏輯時

#務必使用decimal型別

#確認四捨五入邏輯

#明確指定MidpointRounding模式

才會得到精確的結果

【補充】

留言中有人有提到.net預設的 ToEven

也就是 Banker's rounding

兩種四捨五入設計給不同的用途

開發前務必確認四捨五入的邏輯

2018年8月5日 星期日

[pi-nas] pi 增加 SmartMonTools

Smart Mon Tools 是用來看硬碟上 S.M.A.R.T 的資訊,
可以提前知道硬碟是不是快壞了。
對於 NAS 來說是必要的。
但因為樹莓派原先不是用來當 NAS 的,所以沒有預載這個程式。
因此要手動安裝。

sudo apt-get smartmontools

因為很久沒有去動它,所以有可能會遇到站台不見的情況而遇到 unable to fetch some archives 的情況。此時,先執行 sudo apt-get update 再試。

sudo smartctl --all /dev/sda

這樣就可以看到該硬碟所有資訊。

以下的是正常的硬碟
=== START OF READ SMART DATA SECTION ===
SMART overall-health self-assessment test result: PASSED
如果看到以下的文字,就應該要考慮換硬碟了。

=== START OF READ SMART DATA SECTION ===
SMART overall-health self-assessment test result: FAILED!
Drive failure expected in less than 24 hours. SAVE ALL DATA.
See vendor-specific Attribute list for failed Attributes.
接下來找時間來換硬碟,會記錄 gluster 換硬碟的流程,免得又忘記了。

2018年8月1日 星期三

[git]用工具的還是人

一則臉書貼文,有關 git 之前大家怎麼版控的。
https://www.facebook.com/groups/git.tw/permalink/1817171478331512/
樓主留言問到:「想請教一下各位前輩
知道在沒有git 或 svn之類的軟體出現之前
是怎麼協同開發的...

剛剛跟公司的高層主管(不會寫程式)聊天
他說我們公司DevOps很奇怪
為什麼都沒辦法協同開發
說到協同開發每個人都一臉大便

我跟他說很多點公司的現況
1.git當備份工具 commit都沒有意義 更別說開分支之類的
2.大家都是直接連到伺服器去改程式
3.沒有人來負責merge程式
之類的

就被他反嗆
他們1X年前沒用這些東西
大家也都是連到同一台伺服器去做
照樣都可以協同開發
系統也更新了好幾代
為什麼現在不行...
所以想了解一下早期1X年以前
git svn這些東西出現以前
是怎麼協同開發的」

結果有滿多留言不是在回答「git svn這些東西出現以前
是怎麼協同開發的」,而是在講主管有問題。
如果是你,應該怎麼回答這問題呢?

也許樓主是來討拍的,而講主管有問題的才是正確解答。
但我還是留言以前經歷過的協同開發怎麼做的:「Code review, 專人merge 。之後有rational, source safe, cvs,就有辦法一個人改的時侯check out鎖檔不讓別人改,改完check in。」

當然,有些人講得沒錯,現在的程式複雜度比較高,沒有工具就很難處理好。
可以說,因為現在工具的存在,才會出現現在程式的高複雜度。
但反過來說也對,因為有高複雜度的程式的需求,才會造成現在工具的誕生。
但是,重要的還是,不會用工具的人還是會搞得一團糟。
人的概念、程式複雜度、工具支援度,三個東西是程度相合的。其中一個跟不上,就必定出問題,就必定要調整。

最後,我只能留以下留言給事主:
「如果你推不動其他資深同事,那就跟老闆說清楚。
你講的123點,不論用什麼工具都是必須要人們去做好的。
工具再好,人亂用,還是一塌糊塗。
用工具卡死、強迫一定要做到123點,每個 commit 要送老闆簽核、只有某些人才有辦法 merge 進版…等都有辦法做到,以前的幾個 source control software 都做得到。但是如此做會面對更多人性的挑戰,因為那是用伺服器就開始卡權限的,一個人不在位子上,就有可能整個公司不用改程式,一定更多人會抱怨。
工具會進步,就代表舊的方式需要捨棄一些東西來換取另一些東西。git 就是捨棄嚴格卡控,換來靈活合併與分支。如果同事們沒有相對應的概念,就容易弄得更亂。
這時候你們要想想該選擇哪種合作模式才是適合你們這群人,看是要改模式還是換工具或是換公司。」

以上幾點感想。

2018年5月8日 星期二

[googleIO] 2018 年 Google IO 講題分類統計

2018 Google IO 已經開始,從講題分類統計,看今年 Google 的重點方向。

今年的分類跟去年差不多,統計如下:

AR & VR: 13
Accessibility: 8
Ads: 8
Android & Play: 122
Assistant: 24
Cloud: 33
Design: 28
Firebase: 26
Flutter: 11
Identity: 13
IoT: 18
Keynote: 13
Location & Map: 6
Machine Learning & AI: 26
MISC: 38
Nest: 1
OpenSource: 2
Payment: 6
Web: 53

今年很強調 Android,Web。


去年的重點統計:
Firebase 場數有 24 場
Mobile Web 場數有 20 場
Cloud 為 12,Android 為 11。

2018年4月3日 星期二

[git]form hg to git (windows)

目前主要趨勢底定是 git。得要先把 hg 的專案轉到 git 來。

我在 windows 有裝 tortoisehg,所以作法如下:

(1) 在 tortoisehg 的 global settings 裡,把 extension hggit 打開。
(2) 在 bitbucket 開一個 git repo。假設路徑為 https://bitbucket.org/username/hg-projectname-git
(3) 在原來的 hg 的目錄下,執行以下命令,產生 git 的頭:
hg bookmark -r default master
(4)  在原來的 hg 的目錄下,執行以下命令,把歷史推上去:
hg push git+https://bitbucket.org/username/hg-projectname-git
(5) 用 git clone 新路徑。之後就用這個新的 git clone 目錄工作。

打完收工

注意事項:

(1) tortoiseplink 已經失效,所以 hg push git+ssh 這個指令會失敗。我找不到辦法換成 ssh.exe,所以就用 https 的方式。
(2) hg push 的路徑不要用 https://username@bitbucket.org 這種,hg 會產生 getaddrinfo 錯誤。



主要參考文章三篇:
http://arr.gr/blog/2011/10/bitbucket-converting-hg-repositories-to-git/

https://mcmblog.azurewebsites.net/using-tortoisehg-with-git/

https://stackoverflow.com/questions/9272233/hg-clone-using-mercurial-throws-getaddrinfo-failed-error-windows-7