git history 명령 2026, fixup·reword·split으로 커밋 이력 수정하는 기준

git history 명령 커밋 이력 수정 흐름을 보여주는 개발자 워크스테이션
커밋 그래프를 다시 쓰는 작업은 편의보다 복구 가능성과 팀 합의가 먼저다.

git history 명령을 검색했다면 단순히 새 Git 명령이 생겼는지가 아니라 과거 커밋을 고치면서 브랜치 스택을 덜 망가뜨릴 방법을 찾는 상황일 가능성이 크다.

결론부터 말하면 혼자 쓰는 기능 브랜치에서는 실험할 가치가 있지만 공유 브랜치, 릴리스 태그, 병합 커밋이 섞인 이력에서는 보류가 맞다.

Git 공식 문서는 이 명령을 실험적 기능으로 표시하며 동작이 바뀔 수 있다고 적고 있으므로 팀 표준 명령으로 넣기 전에는 작은 저장소에서 검증해야 한다.

핵심 요약
  • git history 명령은 fixup, reword, split로 특정 커밋을 다시 쓰는 실험적 CLI다.
  • 기본 흐름은 descendant local branches까지 갱신할 수 있으므로 --update-refs 범위를 먼저 정해야 한다.
  • 병합 커밋과 충돌 가능 구간은 공식 제한에 걸리므로 git rebase --rebase-merges 또는 기존 절차를 써야 한다.
  • 팀 적용은 백업 ref, dry-run, range-diff, 리뷰어 공지, CI 확인을 묶어야 안전하다.

이 글이 필요한 사람

  • PR을 올리기 전 오래된 커밋에 작은 수정만 합치고 싶은 개발자
  • interactive rebase가 잦은 팀에서 커밋 정리 규칙을 만들려는 리드 개발자
  • jj 같은 대안 도구를 검토했지만 기존 Git 워크플로우를 유지해야 하는 조직
  • 커밋 해시 재작성 때문에 CI, 코드 리뷰, 감사 로그가 꼬인 경험이 있는 DevOps 담당자
  • 보호 브랜치와 릴리스 태그가 있는 저장소에서 이력 수정 허용 범위를 정해야 하는 운영팀

git history 명령이 실제로 바꾸는 지점

Git 공식 문서 기준으로 git history 명령은 특정 커밋을 재배열하거나 수정하는 history rewriting 계열 명령이다.

기존 git rebase와 비슷해 보이지만 대상은 커밋 범위 전체가 아니라 특정 커밋을 고치는 작업에 더 가깝다.

가장 큰 차이는 기본적으로 원래 커밋의 descendant가 되는 로컬 브랜치까지 새 이력으로 이동할 수 있다는 점이다.

이 동작은 개인 브랜치 스택에서는 편하지만 다른 사람이 같은 브랜치를 보고 있다면 해시가 바뀌는 순간 리뷰와 CI 기준점이 달라진다.

명령주요 동작먼저 맞는 상황보류할 상황
fixup스테이징한 변경을 과거 커밋에 합친다오타 수정이나 누락 테스트를 이전 커밋에 넣을 때충돌 가능성이 있거나 공유 브랜치일 때
reword과거 커밋 메시지만 다시 작성한다설계 변경 뒤 커밋 설명을 리뷰 기준에 맞출 때감사용 메시지 보존이 필요한 릴리스 이력일 때
split하나의 커밋을 두 커밋으로 나눈다서로 다른 변경이 한 커밋에 섞였을 때선택할 헝크가 너무 많아 리뷰 증거가 흐려질 때
rebase -i여러 커밋을 대화식으로 재배열한다범위 전체를 squash, edit, reorder해야 할 때로컬 브랜치 스택 전체 갱신이 부담일 때

git history 명령은 rebase를 대체하는 만능 명령이 아니라 특정 커밋 수정 작업을 더 좁은 인터페이스로 처리하는 선택지다.

설치보다 먼저 볼 버전과 명령 확인 순서

Git 2.54 릴리스 노트에는 git history 실험 명령과 split 하위 명령이 추가됐다는 항목이 나온다.

Git 2.55 릴리스 노트에는 git history fixup 명령이 추가됐다는 항목이 나온다.

따라서 팀 문서에 넣을 최소 실습 버전은 Git 2.55 이상으로 잡는 편이 덜 헷갈린다.

git --version
# git version 2.55.x 이상인지 먼저 확인

git help history
# 도움말이 열리면 현재 배포판에 명령이 포함된 상태

git history -h
# 하위 명령과 옵션 확인

운영 환경에서 패키지 관리자가 오래된 Git을 제공한다면 이 기능만을 위해 무리하게 업그레이드하지 않는 편이 낫다.

이 경우는 개발자 로컬 실습용 버전과 CI 서버 버전을 분리하고 CI에서는 기존 rebase 검증 절차만 유지하는 선택이 현실적이다.

안전한 실습 저장소를 먼저 만든다

git history 명령은 해시를 다시 쓰는 작업이므로 처음부터 업무 저장소에서 시험하면 복구 대화가 길어진다.

먼저 장난감 저장소 또는 개인 fork에서 세 커밋짜리 이력을 만들고 --dry-run 결과를 눈으로 확인해야 한다.

  1. 새 실습 저장소를 만들고 first, second, third처럼 작고 분리된 커밋을 만든다.
  2. git log --oneline --decorate --graph로 현재 이력을 파일에 저장한다.
  3. backup/before-history-edit 같은 백업 브랜치를 현재 HEAD에 만든다.
  4. 대상 커밋에 적용할 변경을 staged 상태로 두거나 메시지 수정 대상을 고른다.
  5. git history 하위 명령에 --dry-run과 --update-refs=head를 붙여 영향 범위를 확인한다.
  6. 실행 뒤 git range-diff와 git log로 리뷰 가능한 차이만 남았는지 확인한다.

이 절차가 번거롭게 느껴지는 팀이라면 git history 명령을 아직 팀 표준으로 넣을 단계가 아니다.

fixup은 작은 수정에만 맞다

fixup은 현재 스테이징된 변경을 지정한 과거 커밋에 합치고 그 위의 이력을 다시 만든다.

공식 문서는 git commit --fixup 뒤 autosquash rebase를 하는 흐름과 성격이 비슷하다고 설명한다.

다만 기본 update-refs 범위가 branches일 수 있으므로 혼자 쓰는 브랜치가 아니면 head 범위로 줄이는 판단이 필요하다.

# 예시 흐름: 실제 대상 커밋 해시는 본인 저장소에서 확인한다.
git --version
git help history
git status --short
git log --oneline --decorate --graph -12

# 백업 지점 생성
git branch backup/before-history-edit HEAD

# staged 변경을 과거 커밋에 합치기 전 점검
git add path/to/fix.py
git history fixup <target-commit> --dry-run --update-refs=head

# 실제 실행은 dry-run 결과와 리뷰어 공지 후 진행
git history fixup <target-commit> --update-refs=head

git log --oneline --decorate --graph -12
git range-diff backup/before-history-edit...HEAD

이 조건이면 검토할 만하다: PR을 올리기 전이고 대상 커밋 이후 이력이 단순 직선이며 변경이 테스트 한 줄이나 문서 오타 수준이다.

이 경우는 보류해야 한다: 이미 리뷰 코멘트가 커밋 해시에 붙었거나 동료가 같은 브랜치를 기준으로 작업을 시작했다.

reword는 메시지만 고칠 때 쓴다

reword는 지정한 커밋의 메시지를 편집기로 열고 트리 내용은 그대로 둔다.

내용을 건드리지 않는다는 점에서 가장 안전해 보이지만 커밋 해시는 바뀌므로 외부 참조가 있으면 여전히 이력 재작성이다.

git log --oneline --decorate -8
git branch backup/before-reword HEAD

git history reword <target-commit> --dry-run --update-refs=head
git history reword <target-commit> --update-refs=head

git log --oneline --decorate -8
git range-diff backup/before-reword...HEAD

커밋 메시지 규칙이 엄격한 팀에서는 reword를 린트 실패 수정 수단으로 둘 수 있다.

다만 감사 로그가 커밋 메시지와 티켓 번호를 근거로 남는 조직은 메시지 수정 허용 시점을 PR 생성 전으로 제한해야 한다.

split은 리뷰 단위를 다시 만드는 도구다

split은 하나의 커밋 안에서 헝크를 고르고 두 커밋으로 나누는 명령이다.

Git 공식 예시는 git history split HEAD 뒤 대화식 선택을 거쳐 파일 변경을 분리하는 흐름을 보여준다.

실무에서는 기능 변경과 리팩터링이 한 커밋에 섞였을 때 리뷰 비용을 줄이는 목적으로 쓰는 편이 맞다.

git log --stat --oneline -5
git branch backup/before-split HEAD

git history split <target-commit> --dry-run --update-refs=head
git history split <target-commit> --update-refs=head -- path/to/module

git log --stat --oneline -8
git range-diff backup/before-split...HEAD

split은 선택할 헝크가 많을수록 실수 비용이 커진다.

파일이 10개 이상 섞였거나 테스트와 구현이 복잡하게 엮였으면 새 브랜치에서 수동으로 커밋을 다시 구성하는 편이 더 투명하다.

git rebase와 jj 사이에서 고를 기준

git history 명령은 jj의 전체 작업 모델을 Git 안으로 가져오는 도구가 아니다.

jj 문서는 operation log, undo, first-class conflicts 같은 별도 모델을 설명하지만 git history 공식 문서는 충돌 가능 작업을 지원하지 않는다고 못박는다.

선택지강점리스크추천 조건
git history특정 커밋 수정 흐름이 좁고 명확하다실험적 기능이고 merge history 제한이 있다개인 브랜치 스택에서 fixup, reword, split만 필요할 때
git rebase -i오래 검증된 Git 표준 절차다범위가 길면 충돌과 중간 상태 관리가 늘어난다여러 커밋 순서와 squash를 한 번에 조정할 때
git rebase --rebase-merges병합 이력을 고려한 재배치가 가능하다팀마다 숙련도 차이가 크다merge commit이 있는 브랜치를 다뤄야 할 때
jjoperation log와 first-class conflicts가 강하다도구와 워크플로우 전환 비용이 있다팀이 버전관리 모델 자체를 바꿀 준비가 있을 때

이 조건이면 git history를 검토한다: 기존 Git 교육을 유지하면서 작은 커밋 정리만 더 빠르게 만들고 싶다.

이 조건이면 jj 검토로 넘어간다: 충돌을 나중에 해결하거나 작업 로그 기반 undo를 팀 표준으로 원한다.

팀 저장소 적용 전 체크리스트

  • 보호 브랜치에서는 git history 실행을 금지하고 force push 권한을 분리한다.
  • 개인 브랜치라도 PR 생성 뒤에는 리뷰어에게 이력 재작성 사실을 공지한다.
  • 실행 전 backup ref와 git log 스냅샷을 남기고 삭제 기간을 정한다.
  • --dry-run 결과를 저장하고 실제 실행 뒤 git range-diff로 리뷰 가능한 차이를 남긴다.
  • --update-refs=branches는 로컬 브랜치 스택을 이해한 사람에게만 허용한다.
  • 릴리스 태그, 서명 커밋, 감사 대상 커밋은 reword만이라도 금지한다.
  • CI가 통과한 해시를 다시 쓰면 캐시, 아티팩트, 배포 추적 링크가 무효화될 수 있음을 기록한다.

체크리스트의 핵심은 명령 자체보다 이력 재작성 후 누가 어떤 기준으로 새 해시를 신뢰할지 정하는 것이다.

비용·보안·운영 리스크를 숫자가 아니라 조건으로 본다

git history 명령 자체는 무료지만 잘못된 이력 재작성은 리뷰 시간, CI 실행 시간, 배포 추적 복구 시간으로 비용을 만든다.

보안 관점에서는 서명 커밋, 릴리스 태그, 승인된 변경 이력의 무결성이 핵심 위험이다.

운영 관점에서는 원격 브랜치 기준이 바뀌면서 배포 파이프라인과 이슈 트래커가 가리키는 커밋이 달라지는 상황을 먼저 막아야 한다.

리스크확인 질문허용 기준차단 기준
비용이력 재작성 뒤 CI를 다시 돌릴 범위가 큰가작은 기능 브랜치와 제한된 테스트대형 모노레포 전체 테스트 재실행
보안서명 커밋이나 감사 대상 커밋이 포함되는가서명 전 개인 브랜치릴리스 태그와 승인 기록이 붙은 커밋
운영원격 브랜치 사용자와 리뷰어가 있는가혼자 쓰는 로컬 브랜치공유 브랜치 또는 핫픽스 브랜치
복구backup ref와 reflog로 되돌릴 수 있는가복구 명령을 문서화한 상태복구 담당자와 보존 기간이 없는 상태

이 표를 통과하지 못하면 git history가 편해 보여도 기존 rebase 절차나 새 커밋 추가 방식이 더 싸다.

실무 시나리오 1: PR 직전 오타와 테스트 누락을 합칠 때

시나리오는 개인 기능 브랜치에서 세 번째 커밋까지 만든 뒤 첫 번째 커밋의 테스트 파일 한 줄이 빠진 상태다.

이 조건이면 fixup을 쓰되 --update-refs=head로 현재 HEAD만 갱신하고 backup branch를 먼저 만든다.

실행 뒤에는 range-diff에서 테스트 추가 외 변경이 없는지 확인하고 PR 설명에는 이력 정리 후 생성한 새 해시 기준이라고 적는다.

리뷰가 이미 시작됐다면 같은 수정을 새 커밋으로 올리고 squash merge 정책에서 정리하는 편이 리뷰어 비용을 줄인다.

실무 시나리오 2: 리팩터링과 기능 변경이 한 커밋에 섞였을 때

시나리오는 API 응답 필드 변경과 파일명 정리가 같은 커밋에 들어가 리뷰어가 의미 있는 diff를 보기 어려운 상태다.

이 조건이면 split으로 리팩터링 헝크와 기능 변경 헝크를 나눌 수 있지만 파일 이동이 많으면 수동 재구성이 더 안전하다.

split 뒤에는 각 커밋 메시지에 왜 분리했는지를 적고 테스트 결과를 커밋별로 다시 확인해야 한다.

경로별 소유자가 다른 저장소에서는 CODEOWNERS 리뷰 범위가 바뀔 수 있으므로 split 결과를 리뷰어에게 먼저 공유한다.

실무 시나리오 3: 메시지 규칙만 맞추고 싶을 때

시나리오는 커밋 내용은 맞지만 티켓 번호나 conventional commit prefix가 누락돼 자동 릴리스 노트가 실패한 상태다.

이 조건이면 reword가 가장 좁은 수정이다.

하지만 자동 릴리스가 이미 실행됐거나 커밋 서명이 검증 자료로 남았으면 메시지 수정 대신 후속 메타 커밋이나 릴리스 노트 수동 보정을 선택한다.

정책 스켈레톤: 팀 표준에 넣기 전 문서화할 항목

아래 YAML은 실제 도입 전 팀 위키나 저장소 운영 문서에 옮겨 적을 수 있는 기준 스켈레톤이다.

# git-history-safe-rewrite.yaml
# 목적: git history 명령을 팀 저장소에 도입하기 전 안전 기준을 고정한다.
# 실제 저장소명, 브랜치명, 계정명, 토큰 값은 환경별 설정으로 분리한다.

scope:
  command_family: git history
  allowed_subcommands:
    - fixup
    - reword
    - split
  experimental_command: true
  minimum_git_version_for_trial: "2.55"

repository_rules:
  allow_on_private_feature_branch: true
  allow_on_shared_feature_branch: false
  allow_on_protected_branch: false
  allow_after_pull_request_review_started: conditional
  allow_after_release_tag_created: false

preflight:
  require_clean_worktree: true
  require_backup_ref: true
  require_dry_run: true
  require_remote_push_check: true
  require_ci_green_before_force_push: true
  require_reviewer_notice: true

update_refs:
  default_mode: head
  branches_mode_allowed_only_in_solo_branch_stack: true
  explain_before_use: "branches mode rewrites descendant local branches"

stop_conditions:
  - merge_commit_exists_in_target_range
  - conflict_expected
  - branch_has_remote_collaborator
  - signed_release_tag_depends_on_commit
  - compliance_audit_requires_original_hash
  - hotfix_or_incident_branch

review_evidence:
  save_before_log: true
  save_after_log: true
  save_range_diff: true
  save_reflog_hint: true
  owner_approval_required_for_shared_branch: true

이 스켈레톤의 목적은 명령 사용을 장려하는 것이 아니라 허용 조건과 중단 조건을 같은 문서에 두는 것이다.

특히 shared feature branch와 protected branch를 같은 허용 범위로 묶으면 사고가 난다.

사전 점검 스크립트 예시

아래 스크립트는 실행 전에 브랜치, 작업 트리, 최근 병합 커밋, upstream 차이를 확인하는 보수적인 preflight 예시다.

#!/usr/bin/env python3
# git_history_preflight.py
# 목적: git history fixup/reword/split 실행 전 로컬 저장소의 위험 조건을 빠르게 확인한다.
# 실제 팀 정책은 protected branch 목록, 원격 이름, CI 상태 API와 연결해 확장한다.

from __future__ import annotations
import subprocess
import sys


def run(args: list[str]) -> str:
    result = subprocess.run(args, text=True, capture_output=True)
    if result.returncode != 0:
        raise RuntimeError(result.stderr.strip() or result.stdout.strip())
    return result.stdout.strip()


def git(*args: str) -> str:
    return run(["git", *args])


def main() -> int:
    branch = git("branch", "--show-current")
    if branch in {"main", "master", "release", "prod"}:
        print(f"BLOCK: protected-like branch: {branch}")
        return 2

    status = git("status", "--porcelain")
    if status:
        print("BLOCK: worktree is not clean or staged state is ambiguous")
        print(status)
        return 2

    upstream = subprocess.run(["git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"], text=True, capture_output=True)
    if upstream.returncode == 0:
        ahead_behind = git("rev-list", "--left-right", "--count", f"{upstream.stdout.strip()}...HEAD")
        print(f"INFO: upstream={upstream.stdout.strip()} ahead_behind={ahead_behind}")

    merge_count = git("rev-list", "--merges", "--count", "HEAD~20..HEAD")
    if merge_count != "0":
        print("BLOCK: recent history contains merge commits; git history docs recommend git rebase --rebase-merges instead")
        return 2

    before = git("log", "--oneline", "--decorate", "-12")
    print("OK: save this before-log before running git history")
    print(before)
    print("NEXT: create a backup ref, run git history --dry-run, then compare with git range-diff")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

이 스크립트는 모든 조직 정책을 대신하지 않지만 최소한 깨끗한 작업 트리와 병합 커밋 제한을 자동으로 확인하게 만든다.

실제 환경에서는 GitHub, GitLab, Bitbucket API로 PR 상태와 보호 브랜치 규칙을 조회하는 단계까지 붙이는 편이 좋다.

운영팀이 남겨야 할 복구 메모

git history 명령 실행 전후에는 사람에게 설명 가능한 복구 메모가 있어야 한다.

  • 실행 전 HEAD와 대상 커밋 해시를 기록한다.
  • backup branch 이름과 삭제 예정일을 기록한다.
  • dry-run 출력 또는 예상 update-ref 결과를 저장한다.
  • 실행 후 git range-diff 결과를 PR이나 내부 티켓에 첨부한다.
  • force push가 필요하면 영향을 받는 리뷰어와 브랜치 소비자에게 먼저 알린다.
  • 문제가 생기면 backup branch로 되돌리는 명령을 같은 티켓에 남긴다.

복구 메모가 없으면 명령 성공 여부와 무관하게 운영 실패다.

함께 보면 좋은 글

GitHub Actions CI/CD 비용 2026, Copilot CLI·러너·보관까지 줄이는 운영 기준 썸네일GitHub Actions CI/CD 비용 2026, Copilot CLI·러너·보관까지 줄이는 운영 기준GitHub 통계 대시보드 2026, README 카드보다 먼저 볼 API·캐시·보안 기준 썸네일GitHub 통계 대시보드 2026, README 카드보다 먼저 볼 API·캐시·보안 기준OpenAI Codex 사용법 2026, 설치·CLI·IDE 첫 작업 가이드 썸네일OpenAI Codex 사용법 2026, 설치·CLI·IDE 첫 작업 가이드Claude Code 사용법 2026, 설치·로그인·첫 작업과 보안 승인 기준 썸네일Claude Code 사용법 2026, 설치·로그인·첫 작업과 보안 승인 기준Bash 세그폴트 디버깅 2026, CI에서 쉘 오류를 재현·추적하는 기준 썸네일Bash 세그폴트 디버깅 2026, CI에서 쉘 오류를 재현·추적하는 기준AI 코딩 테스트 자동화 2026, 평가 봇 도입 전 보안·비용·품질 기준 썸네일AI 코딩 테스트 자동화 2026, 평가 봇 도입 전 보안·비용·품질 기준

자주 묻는 질문

git history 명령은 언제부터 쓸 수 있나요?

공식 릴리스 노트 기준으로 Git 2.54에서 실험 명령과 split 항목이 보이고 Git 2.55에서 fixup 항목이 추가됐으므로 실습 기준은 Git 2.55 이상으로 잡는 편이 안전하다.

git history fixup은 git commit --fixup과 무엇이 다른가요?

둘 다 과거 커밋에 작은 수정을 합치는 목적이 있지만 git history fixup은 staged 변경을 대상 커밋에 적용하고 descendant local branches까지 갱신할 수 있다는 점을 먼저 봐야 한다.

공유 브랜치에서도 git history 명령을 써도 되나요?

공유 브랜치에서는 기본적으로 보류가 맞고 정말 필요하면 리뷰어 공지, backup ref, dry-run, range-diff, CI 재검증을 완료한 뒤 제한적으로만 처리해야 한다.

병합 커밋이 있는 이력에서도 동작하나요?

Git 공식 문서는 merge가 포함된 history에는 아직 동작하지 않는다고 설명하므로 이 경우에는 git rebase --rebase-merges 같은 기존 절차를 검토해야 한다.

jj를 쓰면 git history 명령이 필요 없나요?

jj는 operation log와 first-class conflicts 같은 다른 작업 모델을 제공하므로 팀이 도구 전환을 감당할 수 있으면 별도 검토 대상이고 기존 Git 유지가 우선이면 git history가 작은 보완책이 된다.

실패하면 어떻게 되돌리나요?

실행 전 backup branch를 만들었다면 해당 브랜치를 기준으로 reset하거나 새 브랜치를 만들 수 있고 reflog도 보조 복구 수단이 되지만 원격에 push한 뒤에는 팀 조율이 먼저다.

출처와 확인일

GeekNews는 주제 발견 신호로만 사용했고 명령 동작과 제한은 Git 공식 문서, Git 릴리스 노트, jj 공식 문서를 기준으로 정리했다.

git history 명령은 공식 문서에서 실험적 기능으로 표시되므로 동작, 옵션, 지원 범위는 이후 Git 릴리스에서 바뀔 수 있다.

보안, 감사, 릴리스 운영이 걸린 저장소에서는 이 글의 예시만으로 정책을 확정하지 말고 저장소 관리자와 보안 담당자의 검토를 거쳐야 한다.

Tech in Depth tnals1569@gmail.com

댓글

이 블로그의 인기 게시물

구글 홈 앱과 스마트싱스 연동 방법: 스마트홈 완벽 설정 가이드

Claude 주간 사용량 얼마야 | Pro / Max 플랜 주간 한도 & 효율 사용법

이글루 홈캠 vs 파인뷰 홈캠 비교: 화각, 보안, 가격까지 완벽 분석하기