요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
=====================================
Handling messy pull-request diffstats
=====================================
Subsystem maintainers routinely use ``git request-pull`` as part of the
process of sending work upstream. Normally, the result includes a nice
diffstat that shows which files will be touched and how much of each will
be changed. Occasionally, though, a repository with a relatively
complicated development history will yield a massive diffstat containing a
great deal of unrelated work. The result looks ugly and obscures what the
pull request is actually doing. This document describes what is happening
and how to fix things up; it is derived from The Wisdom of Linus Torvalds,
found in Linus1_ and Linus2_.
.. _Linus1: https://lore.kernel.org/lkml/CAHk-=wg3wXH2JNxkQi+eLZkpuxqV+wPiHhw_Jf7ViH33Sw7PHA@mail.gmail.com/
.. _Linus2: https://lore.kernel.org/lkml/CAHk-=wgXbSa8yq8Dht8at+gxb_idnJ7X5qWZQWRBN4_CUPr=eQ@mail.gmail.com/
A Git development history proceeds as a series of commits. In a simplified
manner, mainline kernel development looks like this::
... vM --- vN-rc1 --- vN-rc2 --- vN-rc3 --- ... --- vN-rc7 --- vN
If one wants to see what has changed between two points, a command like
this will do the job::
$ git diff --stat --summary vN-rc2..vN-rc3
Here, there are two clear points in the history; Git will essentially
"subtract" the beginning point from the end point and display the resulting
differences. The requested operation is unambiguous and easy enough to
understand.
When a subsystem maintainer creates a branch and commits changes to it, the
result in the simplest case is a history that looks like::
... vM --- vN-rc1 --- vN-rc2 --- vN-rc3 --- ... --- vN-rc7 --- vN
|
+-- c1 --- c2 --- ... --- cN
If that maintainer now uses ``git diff`` to see what has changed between
the mainline branch (let's call it "linus") and cN, there are still two
clear endpoints, and the result is as expected. So a pull request
generated with ``git request-pull`` will also be as expected. But now
consider a slightly more complex development history::
... vM --- vN-rc1 --- vN-rc2 --- vN-rc3 --- ... --- vN-rc7 --- vN
| |
| +-- c1 --- c2 --- ... --- cN
| /
+-- x1 --- x2 --- x3
Our maintainer has created one branch at vN-rc1 and another at vN-rc2; the
two were then subsequently merged into c2. Now a pull request generated
for cN may end up being messy indeed, and developers often end up wondering
why.
What is happening here is that there are no longer two clear end points for
the ``git diff`` operation to use. The development culminating in cN
started in two different places; to generate the diffstat, ``git diff``
ends up having pick one of them and hoping for the best. If the diffstat
starts at vN-rc1, it may end up including all of the changes between there
and the second origin end point (vN-rc2), which is certainly not what our
maintainer had in mind. With all of that extra junk in the diffstat, it
may be impossible to tell what actually happened in the changes leading up
to cN.
Maintainers often try to resolve this problem by, for example, rebasing the
branch or performing another merge with the linus branch, then recreating
the pull request. This approach tends not to lead to joy at the receiving
end of that pull request; rebasing and/or merging just before pushing
upstream is a well-known way to get a grumpy response.
So what is to be done? The best response when confronted with this
situation is to indeed to do a merge with the branch you intend your work
to be pulled into, but to do it privately, as if it were the source of
shame. Create a new, throwaway branch and do the merge there::
... vM --- vN-rc1 --- vN-rc2 --- vN-rc3 --- ... --- vN-rc7 --- vN
| | |
| +-- c1 --- c2 --- ... --- cN |
| / | |
+-- x1 --- x2 --- x3 +------------+-- TEMP
The merge operation resolves all of the complications resulting from the
multiple beginning points, yielding a coherent result that contains only
the differences from the mainline branch. Now it will be possible to
generate a diffstat with the desired information::
$ git diff -C --stat --summary linus..TEMP
Save the output from this command, then simply delete the TEMP branch;
definitely do not expose it to the outside world. Take the saved diffstat
output and edit it into the messy pull request, yielding a result that
shows what is really going on. That request can then be sent upstream.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
복잡한 pull-request diffstat 문제
1-19Subsystem maintainer는 upstream으로 작업을 보낼 때 흔히 `git request-pull`을 사용합니다. 정상적인 출력에는 변경될 file과 각 file의 변경량을 보여 주는 읽기 쉬운 diffstat이 포함됩니다.
하지만 development history가 비교적 복잡한 repository에서는 관련 없는 작업이 대량으로 포함된 거대한 diffstat이 나올 수 있습니다. 이 결과는 pull request가 실제로 하는 일을 가립니다.
이 문서는 그런 현상이 생기는 이유와 수정 방법을 설명합니다. 내용은 Linus Torvalds의 두 LKML 설명인 `Linus1_`, `Linus2_`에서 가져왔습니다.
Pull request의 실제 범위와 diffstat 표시 범위가 어긋난 상태입니다.
.. SPDX-License-Identifier: GPL-2.0
=====================================
Handling messy pull-request diffstats
=====================================
Subsystem maintainers routinely use ``git request-pull`` as part of the
process of sending work upstream. Normally, the result includes a nice
diffstat that shows which files will be touched and how much of each will
be changed. Occasionally, though, a repository with a relatively
complicated development history will yield a massive diffstat containing a
great deal of unrelated work. The result looks ugly and obscures what the
pull request is actually doing. This document describes what is happening
and how to fix things up; it is derived from The Wisdom of Linus Torvalds,
found in Linus1_ and Linus2_.
.. _Linus1: https://lore.kernel.org/lkml/CAHk-=wg3wXH2JNxkQi+eLZkpuxqV+wPiHhw_Jf7ViH33Sw7PHA@mail.gmail.com/
.. _Linus2: https://lore.kernel.org/lkml/CAHk-=wgXbSa8yq8Dht8at+gxb_idnJ7X5qWZQWRBN4_CUPr=eQ@mail.gmail.com/
명확한 두 endpoint
20-34단순화한 mainline history는 `vN-rc1`, `vN-rc2`, `vN-rc3`처럼 commit이 한 줄로 이어집니다. `git diff --stat --summary vN-rc2..vN-rc3`는 시작점과 끝점이 분명합니다.
Git은 시작점을 끝점에서 사실상 빼고 남은 차이를 표시합니다. 비교할 두 지점이 모호하지 않으므로 원하는 변경량을 쉽게 얻습니다.
원문의 ASCII history를 동일한 의미의 순서 흐름으로 옮겼습니다.
A Git development history proceeds as a series of commits. In a simplified
manner, mainline kernel development looks like this::
... vM --- vN-rc1 --- vN-rc2 --- vN-rc3 --- ... --- vN-rc7 --- vN
If one wants to see what has changed between two points, a command like
this will do the job::
$ git diff --stat --summary vN-rc2..vN-rc3
Here, there are two clear points in the history; Git will essentially
"subtract" the beginning point from the end point and display the resulting
differences. The requested operation is unambiguous and easy enough to
understand.
단일 base와 복수 base branch
35-58Subsystem maintainer가 `vN-rc2`에서 branch를 만들고 `c1`부터 `cN`까지 commit을 쌓은 단순한 경우에도 mainline의 `linus`와 `cN`이라는 두 endpoint가 명확합니다. 따라서 `git diff`와 `git request-pull`은 예상한 결과를 만듭니다.
문제는 한 branch를 `vN-rc1`에서, 다른 branch를 `vN-rc2`에서 만들고, `x1`·`x2`·`x3` branch를 나중에 `c2`로 merge한 경우입니다. 최종 `cN`에 도달한 development가 서로 다른 두 출발점을 가지게 됩니다.
한 mainline 지점에서 파생된 history는 비교 기준이 하나입니다.
원문의 두 갈래 ASCII history를 branch별 단계로 재구성했습니다.
When a subsystem maintainer creates a branch and commits changes to it, the
result in the simplest case is a history that looks like::
... vM --- vN-rc1 --- vN-rc2 --- vN-rc3 --- ... --- vN-rc7 --- vN
|
+-- c1 --- c2 --- ... --- cN
If that maintainer now uses ``git diff`` to see what has changed between
the mainline branch (let's call it "linus") and cN, there are still two
clear endpoints, and the result is as expected. So a pull request
generated with ``git request-pull`` will also be as expected. But now
consider a slightly more complex development history::
... vM --- vN-rc1 --- vN-rc2 --- vN-rc3 --- ... --- vN-rc7 --- vN
| |
| +-- c1 --- c2 --- ... --- cN
| /
+-- x1 --- x2 --- x3
Our maintainer has created one branch at vN-rc1 and another at vN-rc2; the
two were then subsequently merged into c2. Now a pull request generated
for cN may end up being messy indeed, and developers often end up wondering
why.
원인과 피해야 할 즉석 수정
59-74`cN`의 development가 두 곳에서 시작했으므로 `git diff`가 사용할 명확한 시작 endpoint가 하나로 정해지지 않습니다. Diffstat을 만들기 위해 Git은 시작점 하나를 고를 수밖에 없습니다.
시작점을 `vN-rc1`으로 잡으면 두 번째 출발점인 `vN-rc2`까지의 mainline 변경이 모두 포함될 수 있습니다. 이 불필요한 내용 때문에 `cN`으로 이어진 실제 변경을 알아보기 어려워집니다.
Maintainer는 종종 branch를 rebase하거나 `linus` branch를 한 번 더 merge한 뒤 pull request를 다시 만들려고 합니다. 하지만 upstream으로 보내기 직전에 rebase나 merge해 공개 history를 바꾸는 것은 pull을 받는 maintainer에게 좋지 않은 반응을 부르는 잘 알려진 방식입니다.
표시만 고치려다 전달할 branch history 자체를 바꾸지 않아야 합니다.
What is happening here is that there are no longer two clear end points for
the ``git diff`` operation to use. The development culminating in cN
started in two different places; to generate the diffstat, ``git diff``
ends up having pick one of them and hoping for the best. If the diffstat
starts at vN-rc1, it may end up including all of the changes between there
and the second origin end point (vN-rc2), which is certainly not what our
maintainer had in mind. With all of that extra junk in the diffstat, it
may be impossible to tell what actually happened in the changes leading up
to cN.
Maintainers often try to resolve this problem by, for example, rebasing the
branch or performing another merge with the linus branch, then recreating
the pull request. This approach tends not to lead to joy at the receiving
end of that pull request; rebasing and/or merging just before pushing
upstream is a well-known way to get a grumpy response.
Throwaway branch에서 diffstat만 복구
75-96권장 방법은 pull 대상 branch와 merge하되, 실제로 보낼 branch가 아니라 새 throwaway branch에서 비공개로 수행하는 것입니다. 이 merge는 여러 시작점의 복잡성을 해소해 mainline과의 일관된 결과를 만듭니다.
Temporary merge 결과에는 mainline branch에서 실제 subsystem 작업까지의 차이만 남으므로 `git diff -C --stat --summary linus..TEMP`로 원하는 diffstat을 생성할 수 있습니다.
명령 출력을 저장한 뒤 `TEMP` branch는 삭제하고 외부에 절대 공개하지 않습니다. 저장한 diffstat을 기존의 복잡한 pull request에 편집해 넣으면 실제 변경을 보여 주는 요청을 upstream으로 보낼 수 있습니다.
전달할 history는 유지하고 표시용 비교 branch만 잠시 만듭니다.
So what is to be done? The best response when confronted with this
situation is to indeed to do a merge with the branch you intend your work
to be pulled into, but to do it privately, as if it were the source of
shame. Create a new, throwaway branch and do the merge there::
... vM --- vN-rc1 --- vN-rc2 --- vN-rc3 --- ... --- vN-rc7 --- vN
| | |
| +-- c1 --- c2 --- ... --- cN |
| / | |
+-- x1 --- x2 --- x3 +------------+-- TEMP
The merge operation resolves all of the complications resulting from the
multiple beginning points, yielding a coherent result that contains only
the differences from the mainline branch. Now it will be possible to
generate a diffstat with the desired information::
$ git diff -C --stat --summary linus..TEMP
Save the output from this command, then simply delete the TEMP branch;
definitely do not expose it to the outside world. Take the saved diffstat
output and edit it into the messy pull request, yielding a result that
shows what is really going on. That request can then be sent upstream.
요약·해설
messy-diffstat.rst:1-96서로 다른 mainline 지점에서 시작한 branch를 합치면 `git request-pull` diffstat에 관련 없는 mainline 변경이 섞일 수 있습니다.
실제 전달 branch를 rebase하거나 merge하지 않고 throwaway `TEMP` branch에서 target을 merge해 diffstat만 뽑은 뒤 branch를 삭제하는 것이 권장됩니다.