과거에 Git 커밋을 어떻게합니까? 사용하기 위해 모든 것을 Git으로 변환하고

개인적으로 사용하기 위해 모든 것을 Git으로 변환하고 있으며 저장소에 이미 오래된 버전의 파일이 있습니다. 파일의 “수정 날짜”에 따라 올바른 순서로 기록에 커밋하려면 어떻게 파일의 정확한 기록을 갖습니까?

나는 이것이 효과가 있다고 들었다.

git filter-branch --env-filter="GIT_AUTHOR_DATE=... --index-filter "git commit path/to/file --date " --tag-name-filter cat -- --all


답변

당신이받은 조언에 결함이 있습니다. 무조건 GIT_AUTHOR_DATE를 설정하면 --env-filter모든 커밋 날짜가 다시 작성됩니다. 또한 git commit inside 를 사용하는 것은 드문 일 --index-filter입니다.

여기서 여러 개의 독립적 인 문제를 처리하고 있습니다.

“지금”이외의 날짜 지정

각 커밋에는 작성자 날짜와 커미터 날짜의 두 날짜가 있습니다. 새 커밋을 작성하는 모든 명령에 대해 환경 변수 GIT_AUTHOR_DATE 및 GIT_COMMITTER_DATE를 통해 값을 제공하여 각각을 대체 할 수 있습니다. git-commit (1) 또는 아래의 “날짜 형식”을 참조하십시오 .

Git internal format = <unix timestamp> <time zone offset>, e.g.  1112926393 +0200
RFC 2822            = e.g. Thu, 07 Apr 2005 22:13:13 +0200
ISO 8601            = e.g. 2005-04-07T22:13:13

정상적인 사용 중에 새 커밋을 작성하는 유일한 명령은 git commit 입니다. --date작성자 날짜를 직접 지정할 수 있는 옵션도 있습니다. 예상 사용량에는 git filter-branch --env-filter위에서 언급 한 환경 변수도 사용됩니다 (이 옵션은 옵션 이름을 지정한 후 “env”의 일부입니다. git-filter-branch (1)의 “옵션” 및 기본 “배관”명령 git-commit -tree (1) .

단일 참조 기록에 파일 삽입

리포지토리가 매우 간단한 경우 (즉, 태그가없는 단일 분기 만있는 경우) git rebase 를 사용 하여 작업을 수행 할 수 있습니다.

다음 명령에서“A”대신 커밋의 객체 이름 (SHA-1 해시)을 사용하십시오. git commit 을 실행할 때 “date override”메소드 중 하나를 사용하는 것을 잊지 마십시오 .

---A---B---C---o---o---o   master

git checkout master
git checkout A~0
git add path/to/file
git commit --date='whenever'
git tag ,new-commit -m'delete me later'
git checkout -
git rebase --onto ,new-commit A
git tag -d ,new-commit

---A---N                      (was ",new-commit", but we delete the tag)
        \
         B'---C'---o---o---o   master

추가 된 위치에 새 커밋을 작성하는 대신 새 파일을 포함하도록 A를 업데이트하려면 git commit --amend대신 을 사용하십시오 git commit. 결과는 다음과 같습니다.

---A'---B'---C'---o---o---o   master

위의 내용은 새 커밋의 부모가되어야하는 커밋의 이름을 지정할 수있는 한 작동합니다. 실제로 새로운 루트 커밋 (부모 없음)을 통해 새 파일을 추가하려면 약간 다른 것이 필요합니다.

B---C---o---o---o   master

git checkout master
git checkout --orphan new-root
git rm -rf .
git add path/to/file
GIT_AUTHOR_DATE='whenever' git commit
git checkout -
git rebase --root --onto new-root
git branch -d new-root

N                       (was new-root, but we deleted it)
 \
  B'---C'---o---o---o   master

git checkout --orphan상대적으로 새롭지 만 (Git 1.7.2), 이전 버전의 Git에서 작동 하는 것과 동일한 작업을 수행하는 다른 방법이 있습니다.

다중 참조 기록에 파일 삽입

저장소가 더 복잡한 경우 (즉, 하나 이상의 참조 (분기, 태그 등)가있는 경우) git filter-branch 를 사용해야 할 것입니다 . git filter-branch를 사용하기 전에 전체 저장소의 백업 사본을 작성해야합니다. 전체 작업 트리 의 간단한 tar 아카이브 (.git 디렉토리 포함)로 충분합니다. git filter-branch 는 백업 참조를 만들지 만 .git디렉토리를 삭제 하고 백업에서 복원 하여 바로 올바른 필터링에서 복구하는 것이 더 쉬운 경우가 많습니다 .

참고 : 아래 예는 git update-index --add대신 하위 수준 명령을 사용 git add합니다. git add를 사용할 수는 있지만 먼저 외부 위치에서 예상 경로로 파일을 복사해야합니다 ( --index-filter빈 임시 GIT_WORK_TREE에서 명령을 실행).

모든 기존 커밋에 새 파일을 추가하려면 다음을 수행하십시오.

new_file=$(git hash-object -w path/to/file)
git filter-branch \
  --index-filter \
    'git update-index --add --cacheinfo 100644 '"$new_file"' path/to/file' \
  --tag-name-filter cat \
  -- --all
git reset --hard

기존 커밋 날짜를 변경해야 할 이유가 없습니다 --env-filter 'GIT_AUTHOR_DATE=…'. 그것을 사용했다면, 모든 커밋에 대한 날짜를 다시 쓰도록 조건부로 만들 것입니다.

기존의 커밋 (“A”) 후에 커밋에만 새 파일을 표시하려면 다음을 수행하십시오.

file_path=path/to/file
before_commit=$(git rev-parse --verify A)
file_blob=$(git hash-object -w "$file_path")
git filter-branch \
  --index-filter '

    if x=$(git rev-list -1 "$GIT_COMMIT" --not '"$before_commit"') &&
       test -n "$x"; then
         git update-index --add --cacheinfo 100644 '"$file_blob $file_path"'
    fi

  ' \
  --tag-name-filter cat \
  -- --all
git reset --hard

히스토리 중간에 삽입 할 새 커밋을 통해 파일을 추가 하려면 git filter-branch 를 사용하기 전에 새 커밋을 생성하고 git filter-branch 에 추가 --parent-filter해야합니다 .

file_path=path/to/file
before_commit=$(git rev-parse --verify A)

git checkout master
git checkout "$before_commit"
git add "$file_path"
git commit --date='whenever'
new_commit=$(git rev-parse --verify HEAD)
file_blob=$(git rev-parse --verify HEAD:"$file_path")
git checkout -

git filter-branch \
  --parent-filter "sed -e s/$before_commit/$new_commit/g" \
  --index-filter '

    if x=$(git rev-list -1 "$GIT_COMMIT" --not '"$new_commit"') &&
       test -n "$x"; then
         git update-index --add --cacheinfo 100644 '"$file_blob $file_path"'
    fi

  ' \
  --tag-name-filter cat \
  -- --all
git reset --hard

로부터의 “고아”방법을 통해 커밋 새 루트를 만들 : 당신은 또한 파일이 처음 커밋 새로운 루트에서 추가로를 준비 할 수 자식 REBASE의 섹션 (캡처 거기에 new_commit무조건을 사용) --index-filter, 그리고 --parent-filter처럼 "sed -e \"s/^$/-p $new_commit/\"".


답변

평소와 같이 커밋을 만들 수 있지만 커밋 할 때 환경 변수 GIT_AUTHOR_DATEGIT_COMMITTER_DATE적절한 날짜 시간을 설정하십시오 .

물론 이것은 분기의 끝에서 (즉, 현재 HEAD 커밋 앞에서) 커밋을 수행합니다. repo에서 더 멀리 밀어 넣으려면 약간 화려해야합니다. 이 역사가 있다고 가정 해 봅시다.

o--o--o--o--o

그리고 새로운 커밋 ( “X”로 표시)이 두 번째 로 나타나기를 원합니다 .

o--X--o--o--o--o

가장 쉬운 방법은 첫 번째 커밋에서 분기하고 새 커밋을 추가 한 다음 새 커밋 위에 다른 커밋을 리베이스하는 것입니다. 이렇게 :

$ git checkout -b new_commit $desired_parent_of_new_commit
$ git add new_file
$ GIT_AUTHOR_DATE='your date' GIT_COMMITTER_DATE='your date' git commit -m 'new (old) files'
$ git checkout master
$ git rebase new_commit
$ git branch -d new_commit

답변

나는이 질문이 꽤 오래되었다는 것을 알고 있지만 실제로 나를 위해 일한 것입니다.

git commit --date="10 day ago" -m "Your commit message"

답변

시간이 지남에 따라 myfile 의 많은 버전을 myfile_bak, myfile_old, myfile_2010, backups / myfile 등으로 저장했습니다. 수정 날짜를 사용하여 myfile의 기록을 git에 저장하고 싶었습니다. 그래서 myfile을하는 가장 오래된 이름을 변경 git add myfile한 후 git commit --date=(modification date from ls -l) myfile, myfile을 옆에 오래된 이름을 변경, 다른 자식은 –date, 반복과 함께 커밋 …

이를 다소 자동화하기 위해 shell-foo를 사용하여 파일의 수정 시간을 얻을 수 있습니다. 내가 시작 ls -l하고 cut, 그러나 합계 (1) 더 직접적

git commit --date = "`stat -c % y myfile` " myfile

답변

다음은 내가에 변경 사항을 적용하기 위해 무엇을 사용 foo하는 N=1과거의 일 :

git add foo
git commit -m "Update foo"
git commit --amend --date="$(date -v-1d)"

더 오래된 날짜로 커밋하려면 3 일 전에 다시 date인수를 변경하십시오 date -v-3d.

예를 들어 어제 무언가를 저지르는 것을 잊었을 때 정말 유용합니다.

UPDATE : 또는 --datelike와 같은 표현식도 허용합니다 . 따라서 한 줄 명령으로 줄일 수 있습니다.--date "3 days ago"--date "yesterday"

git add foo ; git commit --date "yesterday" -m "Update"

답변

필자의 경우 –date 옵션을 사용하는 동안 git 프로세스가 중단되었습니다. 내가 끔찍한 짓을했을 수도 있습니다. 결과적으로 일부 index.lock 파일이 나타납니다. 그래서 .git 폴더에서 .lock 파일을 수동으로 삭제하고 실행하여 모든 수정 된 파일이 통과 된 날짜에 커밋되어 이번에는 효과가있었습니다. 모든 답변에 감사드립니다.

git commit --date="`date --date='2 day ago'`" -am "update"

답변

그것은 과거에 행해졌처럼 당신이 모두 설정해야 그 모습을 커밋 만들려면 GIT_AUTHOR_DATEGIT_COMMITTER_DATE:

GIT_AUTHOR_DATE=$(date -d'...') GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" git commit -m '...'

여기서 date -d'...'정확히 같은 일이 될 수 2019-01-01 12:00:00또는 같은 상대 5 months ago 24 days ago.

git log에서 두 날짜를 모두 보려면

git log --pretty=fuller

병합 커밋에도 적용됩니다.

GIT_AUTHOR_DATE=$(date -d'...') GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" git merge <branchname> --no-ff