Reputation: 4679
I'm converting everything over to Git for my own personal use and I found some old versions of a file already in the repository. How do I commit it to the history in the correct order according the file's "date modified" so I have an accurate history of the file?
I was told something like this would work:
git filter-branch --env-filter="GIT_AUTHOR_DATE=... --index-filter "git commit path/to/file --date " --tag-name-filter cat -- --all
Upvotes: 466
Views: 276604
Reputation: 122
What I've found works best for me is this.
git add .
git commit --date "1 day ago" -m "commit"
Upvotes: -2
Reputation: 12186
This is what worked for me:
git commit --date "10 day ago" -m "Your commit message"
Upvotes: 427
Reputation: 1841
So if you want to commit something on Git in the past date, you simply use these commands that help you to do so.
git commit --amend --no-edit --date="Sat Jun 5 20:00:00 2021 -0600"
git add .
git commit -m "Your commit message"
.git commit --amend --no-edit --date="Sat Jun 5 20:00:00 2021 -0600"
command after a commit to amend the last commit with the timestamp noted. The --no-edit will leave the message as-is.Make sure you have to change the date and time according to your preference. This will create a commit to the particular date in the past and you do not lose your GitHub streak.
Upvotes: 10
Reputation: 436
git commit --date='year-month-day hour:minutes:seconds' -m "message"
git push
Upvotes: 2
Reputation: 16597
GIT_AUTHOR_DATE="2020-10-24T18:00:00 +0200" GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE git commit
Mind the timezone string and set a proper one for your timezone. i.e. +0200, -0400
Upvotes: 26
Reputation: 917
This is an old question but I recently stumbled upon it.
git commit --date='year-month-day hour:minutes:seconds' -m "message"
So it would look something like this:
git commit --date='2021-01-01 12:12:00' -m "message"
worked properly and verified it on GitHub
and GitLab
.
Upvotes: 90
Reputation: 3911
git --date
changes only GIT_AUTHOR_DATE
but many git apps, e.g., GitHub shows GIT_COMMITTER_DATE
. Make sure to change GIT_COMMITTER_DATE
too.Complete example in OS X (Change both GIT_COMMITTER_DATE
and GIT_AUTHOR_DATE
to 4 hours ago):
x=$(date -v -4H +%Y-%m-%dT%H:%M:%S%z); export GIT_COMMITTER_DATE=$x; git commit --amend --date $x
Upvotes: 12
Reputation: 118
Pre-Step.
Pull all data from the remote to the local repository.
we are using the --amend and --date switches.
The exact command is as follows:
$ git commit --amend --date="YYYY-MM-DD HH:MM:SS"
Upvotes: 5
Reputation: 2441
Or just use a fake-git-history to generate it for a specific data range.
Upvotes: 9
Reputation: 7103
To make a commit that looks like it was done in the past you have to set both GIT_AUTHOR_DATE
and GIT_COMMITTER_DATE
:
GIT_AUTHOR_DATE=$(date -d'...') GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" git commit -m '...'
where date -d'...'
can be exact date like 2019-01-01 12:00:00
or relative like 5 months ago 24 days ago
.
To see both dates in git log use:
git log --pretty=fuller
This also works for merge commits:
GIT_AUTHOR_DATE=$(date -d'...') GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" git merge <branchname> --no-ff
Upvotes: 78
Reputation: 9431
You can always change a date on your computer, make a commit, then change the date back and push.
Upvotes: 4
Reputation: 777
The following is what I use to commit changes on foo
to N=1
days in the past:
git add foo
git commit -m "Update foo"
git commit --amend --date="$(date -v-1d)"
If you want to commit to a even older date, say 3 days back, just change the date
argument: date -v-3d
.
That's really useful when you forget to commit something yesterday, for instance.
UPDATE: --date
also accepts expressions like --date "3 days ago"
or even --date "yesterday"
. So we can reduce it to one line command:
git add foo ; git commit --date "yesterday" -m "Update"
Upvotes: 47
Reputation: 224591
The advice you were given is flawed. Unconditionally setting GIT_AUTHOR_DATE in an --env-filter
would rewrite the date of every commit. Also, it would be unusual to use git commit inside --index-filter
.
You are dealing with multiple, independent problems here.
Each commit has two dates: the author date and the committer date. You can override each by supplying values through the environment variables GIT_AUTHOR_DATE and GIT_COMMITTER_DATE for any command that writes a new commit. See “Date Formats” in git-commit(1) or the below:
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
The only command that writes a new commit during normal use is git commit. It also has a --date
option that lets you directly specify the author date. Your anticipated usage includes git filter-branch --env-filter
also uses the environment variables mentioned above (these are part of the “env” after which the option is named; see “Options” in git-filter-branch(1) and the underlying “plumbing” command git-commit-tree(1).
If your repository is very simple (i.e. you only have a single branch, no tags), then you can probably use git rebase to do the work.
In the following commands, use the object name (SHA-1 hash) of the commit instead of “A”. Do not forget to use one of the “date override” methods when you run git commit.
---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
If you wanted to update A to include the new file (instead of creating a new commit where it was added), then use git commit --amend
instead of git commit
. The result would look like this:
---A'---B'---C'---o---o---o master
The above works as long as you can name the commit that should be the parent of your new commit. If you actually want your new file to be added via a new root commit (no parents), then you need something a bit different:
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
is relatively new (Git 1.7.2), but there are other ways of doing the same thing that work on older versions of Git.
If your repository is more complex (i.e. it has more than one ref (branches, tags, etc.)), then you will probably need to use git filter-branch. Before using git filter-branch, you should make a backup copy of your entire repository. A simple tar archive of your entire working tree (including the .git directory) is sufficient. git filter-branch does make backup refs, but it is often easier to recover from a not-quite-right filtering by just deleting your .git
directory and restoring it from your backup.
Note: The examples below use the lower-level command git update-index --add
instead of git add
. You could use git add, but you would first need to copy the file from some external location to the expected path (--index-filter
runs its command in a temporary GIT_WORK_TREE that is empty).
If you want your new file to be added to every existing commit, then you can do this:
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
I do not really see any reason to change the dates of the existing commits with --env-filter 'GIT_AUTHOR_DATE=…'
. If you did use it, you would have make it conditional so that it would rewrite the date for every commit.
If you want your new file to appear only in the commits after some existing commit (“A”), then you can do this:
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
If you want the file to be added via a new commit that is to be inserted into the middle of your history, then you will need to generate the new commit prior to using git filter-branch and add --parent-filter
to git filter-branch:
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
You could also arrange for the file to be first added in a new root commit: create your new root commit via the “orphan” method from the git rebase section (capture it in new_commit
), use the unconditional --index-filter
, and a --parent-filter
like "sed -e \"s/^$/-p $new_commit/\""
.
Upvotes: 271
Reputation: 2584
In my case over time I had saved a bunch of versions of myfile as myfile_bak, myfile_old, myfile_2010, backups/myfile etc. I wanted to put myfile's history in git using their modification dates. So rename the oldest to myfile, git add myfile
, then git commit --date=(modification date from ls -l) myfile
, rename next oldest to myfile, another git commit with --date, repeat...
To automate this somewhat, you can use shell-foo to get the modification time of the file. I started with ls -l
and cut
, but stat(1) is more direct
git commit --date="`stat -c %y myfile`" myfile
Upvotes: 46
Reputation: 3693
In my case, while using the --date option, my git process crashed. May be I did something terrible. And as a result some index.lock file appeared. So I manually deleted the .lock files from .git folder and executed, for all modified files to be commited in passed dates and it worked this time. Thanx for all the answers here.
git commit --date="`date --date='2 day ago'`" -am "update"
Upvotes: 22
Reputation: 410552
You can create the commit as usual, but when you commit, set the environment variables GIT_AUTHOR_DATE
and GIT_COMMITTER_DATE
to the appropriate datetimes.
Of course, this will make the commit at the tip of your branch (i.e., in front of the current HEAD commit). If you want to push it back farther in the repo, you have to get a bit fancy. Let's say you have this history:
o--o--o--o--o
And you want your new commit (marked as "X") to appear second:
o--X--o--o--o--o
The easiest way would be to branch from the first commit, add your new commit, then rebase all other commits on top of the new one. Like so:
$ 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
Upvotes: 215