#TIL git patch를 적용하는 apply 명령과 am 명령

GitHub에 있는 커밋을 내 저장소에 적용하고 싶다. 리모트 저장소로 등록을 안 한 상태라서 git cherry-pick 명령은 사용하지 못한다. 어떻게 하면 될까?

프로젝트를 운영하는 것은 크게 두 가지로 이루어진다. 하나는 format-patch 명령으로 생성한 Patch를 이메일로 받아서 프로젝트에 Patch를 적용하는 것이다.

Git - 프로젝트 관리하기 - git-scm.com

patch를 받아서 적용하면 된다. GitHub은 커밋 URL 끝에 .patch 를 붙이면 format-patch 명령으로 만든 형식으로 커밋을 보여주는 기능을 제공한다.

GitHub Doom Emacs 저장소에 있는 9620bb45ac4c 커밋을 적용해 보자

$ curl https://github.com/doomemacs/doomemacs/commit/9620bb45ac4cd7b0274c497b2d9d93c4ad9364ee.patch | git apply --verbose
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1187  100  1187    0     0   1916      0 --:--:-- --:--:-- --:--:--  1917
Checking patch modules/editor/evil/autoload/unimpaired.el...
Applied patch modules/editor/evil/autoload/unimpaired.el cleanly.

git diff 명령으로 patch가 적용됐는지 확인한다.

$ git diff
diff --git a/modules/editor/evil/autoload/unimpaired.el b/modules/editor/evil/autoload/unimpaired.el
index 0e64d427b..b698b56ea 100644
--- a/modules/editor/evil/autoload/unimpaired.el
+++ b/modules/editor/evil/autoload/unimpaired.el
@@ -113,7 +113,7 @@ See `+evil/next-preproc-directive' for details."
     (user-error "Must be called from a file-visiting buffer"))
   (let* ((directory (file-name-directory buffer-file-name))
          (filename (file-name-nondirectory buffer-file-name))
-         (files (cl-remove-if #'file-directory-p (doom-glob (file-name-directory buffer-file-name) "[!.]*")))
+         (files (cl-remove-if-not #'file-regular-p (doom-glob (file-name-directory buffer-file-name) "[!.]*")))
          (index (cl-position filename files :test #'file-equal-p)))
     (when (null index)
       (user-error "Couldn't find this file in current directory"))

잘 된다. 하지만 기여자의 이름이라든지 커밋 메시지는 적용되지 않는다. diff만 적용된다. git format-patch 명령으로 만들면 커밋 메시지를 포함해 기여자의 정보까지 다 기록되어 있다. 이것까지 적용하려면 어떻게 하면 될까?

format-patch 명령으로 생성한 Patch 파일은 git am 명령으로 적용한다(am 은 “apply a series of patches from a mailbox”의 약자다). git am 은 mbox 파일을 읽어 그 안에 이메일 메시지가 한 개가 있든 여러 개가 있든 처리할 수 있다.

Git - 프로젝트 관리하기 - git-scm.com

git am 명령을 사용하면 된다. 이 명령으로 다시 적용해보자.

$ curl https://github.com/doomemacs/doomemacs/commit/9620bb45ac4cd7b0274c497b2d9d93c4ad9364ee.patch | git am
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1187  100  1187    0     0   2026      0 --:--:-- --:--:-- --:--:--  2029
Applying: fix(evil): ]f/[f opening broken symlinks

git apply 명령과 다르게 바로 커밋을 만들어준다.

$ git log -n 1
commit e632775ed333e8ed2088287c2de519463e697c87 (HEAD -> master)
Author: Henrik Lissner <git@henrik.io>
Date:   Thu Apr 18 13:50:28 2024 -0400

    fix(evil): ]f/[f opening broken symlinks

diff외 정보도 잘 보존된다.

참고

Feedback plz <3 @ohyecloudy, ohyecloudy@gmail.com

A Random Post