카테고리 2단계 (끝)

curious programmer

I wrote about crafting changes into small atomic commits using Git. It looked like there was some confusion. I want to share what I understand about atomic and monolithic commits and why I create atomic commits in Git.

I got a question in Reddit by WetDynamics that “atomic commits sound nice in theory but in practice you end up with 100 commits of “extracted foo into a method” or “refactored bar to make it more readable”. Does it really make your git history easier to grok than a single commit focused on a feature?”

I think we are on the same page. I feel as though my intent was not clear in my previous post.

An atomic commit

Let’s say I do a refactor but I also update a some features and add new ones.

In an atomic commit, I will commit the refactor and each feature change separately.

I don’t know what the official definition is but to me an atomic commit is a commit that focuses on one context and one context alone. Granted, this is tricky. I do this to the best of my abilities but I don’t always get it right.

Disclaimer: I don’t intend that I commit each and every single line or function. By context I mean a single topic: a feature, bug fix, refactor, upgrade, task…

A monolithic commit

Again. Let’s say I do a refactor but I also update a some features and add new ones.

The entire changeset gets committed in a monolithic commit.

Granted, it doesn’t have to be a large commit. It’s a commit with changes tightly coupled into a single commit. Like a tangled or spaghetti commit.

The larger the commit, the more brittle and error prone it becomes because it becomes harder to understand (even if it’s well documented - I know this from my own doing), read, review and revert.

Why go atomic?

Atomic commits are easier to:

  • track - I know where they are in the history. git log --oneline shows me all commits. git log --grep <pattern> lets me find a commit based on a partial message. git log <commit> will jump to that commit and show previous commits.

  • understand - I document each change with a commit message and elaborate with an explanation if I need to.

  • read - it’s a change focused on a single context which makes it smaller, simpler and easier to read the patch git show <commit> or git log <commit> -p

  • review - as it’s a small, focused, documented change, a reviewer should be able to follow the code changes and keep their sanity.

  • revert - reverting git revert <commit> an atomic commit will not revert unrelated changes like a monolithic commit would.

What do I do?

  • I try working on one thing - this is not always possible, hence my previous post. This is where I use the interactive mode to my advantage. Most GUIs come with intuitive interfaces.

    git add -i

  • I try keep my changes as small as possible - this makes it easier for me to commit my changes once I am done especially when I go into an interactive mode.

  • I try to commit often - I amend my commits when I need to.

    git commit -m "<message>" --amend

  • I aim to be vigilant that tests pass (I get this wrong sometimes). I want failing/code tests fixed and committed as part of the context commit. Otherwise I have a “broken” commit.

  • When I end up littering my feature commits (features have commits in a random order) then I use an interactive rebase to move and squash the commits prior to pushing them.

    git rebase -i

The goal of creating atomic commits is not to create “100 commits” but rather pragmatically craft relevant changes for a better history, cognitive load and an easier means to rollback changes.

주요 사이트

현재 공부중인 링크

  • .gitconfig 파일에 “git sc” 명령을 만드는데 아이디어를 준 링크
    • SO, How to create a frequency list of every word in a file 답변
    • 캡쳐 쓰는 법 ()로 쌀때, \\( … \\) 로 싸야 함. 부를 때도 \\1
    • [\\1] 안되는 이유는 이어지는 awk 명령이 중간에 공백이 있을때 뒤엣것을 날려버림. 잘 생각해보자 $1만 프린트 하고 있어서 첫번째 공백 이후것은 날아간다.
    • 이 명령이 필요한 이유 : git difftool 에 필터를 쓰기전에 어떤 옵션으로 필터를 쓸지 정하기 위해 필요하다.

git 기본 명령

git config ( 포스팅할것)

git - 카테고리 문서

Github merge 옵션 관련 Github에서 Pull request를 merge 시 git에서 제공하는 여러 merge option을 팀 공유를 위해 간략히 정리함

pullrequest-mergebutton

Github에서 Pull request merge 시 아래 가이드와 같은 merge 방법이 있음.

  • Merge pull request

  • Squash and merge

  • Rebase and merge

Merging a pull request

https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/merging-a-pull-request

각 방법들은 git에서 제공하는 merge 방법으로 아래 가이드를 보면 이해하기가 쉬울 듯함.

About merge methods on GitHub

https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/about-merge-methods-on-github

https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/about-pull-request-merges

브랜치 통합하기

https://backlog.com/git-tutorial/kr/stepup/stepup1_4.html

3.2 Git Branching - Basic Branching and Merging

https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging

https://git-scm.com/docs/git-merge
3.6 Git Branching - Rebasing

https://git-scm.com/book/en/v2/Git-Branching-Rebasing

https://git-scm.com/docs/git-rebase

GitHub 가이드가 가장 깔끔하게 설명을 하고 있어 간략히 발췌하면

Merge pull request는

. Pull request의 모든 commit을 default branch로 추가하고 merge commit을 생성한다.
. git merge 시 –no-ff option을 사용하는 것이라 merge commit을 생성하게 되는 것이다.
이 옵션은 주로 특정 branch나 개발 history를 유지하려는 경우 사용됨.
https://stackoverflow.com/a/14865661
https://koreabigname.tistory.com/m/65

아래 그림을 보면 feature branch에서는 default branch 기반으로 D,E를 생성하였기 때문에 A,B,C 다음 D,E를 추가하면 되지만 merge commit을 생성하여 default branch에 추가하게 된다.

standard-merge-commit-diagram

Squash and merge는

. 용어와 같이 pull request의 commit을 하나로 모아 default branch에 추가하여 merge하게 된다. . Repository 설정에서 squash merging을 허용해야 한다. . 수정/개발 hisotry가 중요하지 않다면 이 옵션을 사용하여 default branch를 깔끔하게 관리할 수도 있겠음.

commit-squashing-diagram

Rebase and merge는

. Pull request의 모든 commit이 head branch에 merge commit 없이 차례로 추가된다. . Git repository에서 rebase merging이 허용되어야 한다. . Github의 rebase는 git rebase와 다른 점이 있는데 git rebase는 committer 정보와 commit SHA를 변경하지 않지만 Github는 변경하는 점이 다르다고 함. . Github에서 자동으로 Rebase and merge가 되지 않는다면 command line에서 rebase를 수행하여 conflict를 해결하고 force push를 해야 함.

다운로드

다만 rebase 수행 시 조심해야 할 점은

. 작업 branch가 default branch에서 분기되어 오래되었다면 merge conflict이 더 자주 발생할 수 있음.

default branch에 대해 자주 rebase하고 commit하면 해결 될 수 있음. 솔직히 Github에서 branch는 필요할 때 마다 만들어 사용하는게 맞는 것 같다.

. Interactive rebase 작업 도중 commit history를 잃어버릴 수 있음.

git reflog를 이용하여 복원하거나 rebase 작업을 취소할 수 있다고 함.

Atlassian Bitbucket git rebase https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase

마지막으로 아래 글은 Git 사용자라면 한 번쯤 봤을 정도로 고전인 article으로 Project 수행 시 어떻게 branch를 관리하면 좋을지에 대한 내용이니 꼭 읽어보고 알아두어야 함.

A successful Git branching model

https://nvie.com/posts/a-successful-git-branching-model/ git-model@2x

The following wiki, pages and posts are tagged with

TitleTypeExcerpt
working with git remotes post Thu, Oct 21, 21, the nugget is to push to both branches in one command
playing detectives to restore my sanity when something terribly wrong post Thu, Oct 21, 21, refactor move delete and remove differ-filter rev-list to restore lost files
Github created first time post Mon, Nov 01, 21, ssh token key created first time
Clone Mirroring post Wednesday, how to clone a repo with all branches and push to a new location
Git-Category.md post 카테고리 2단계 (끝)
gitteam book summary page summary.
dotfiles.md post powershell 환경설정
excel2gsheet.md post google-apps-script를 배우는 좋은 시작점
git-commands.md post git 명령어 상황별 레시피
Github actions a vendor contest page summary.
contents deploy automation page Pilot test on the automation prototype.
docker learning curve page summary.
github team page summary.
git config page summary.
gitlab page summary.
Nextcloud page summary.
Automation pipeline page summary.
🔭raspberry pi project page summary.
wehbook deploy automation page summary.