3

When I need to change the commit dates of various commits, I use an interactive rebase and change them one by one.

How could I change them all in a single command ? In other words, I need to apply a given command to all commits that would be listed in an interactive rebase.

Thanks

HagridV
  • 81
  • 1
  • 7

3 Answers3

5

Filter-Repo

git filter-branch is deprecated. Instead, use git filter-repo. You will need to install it.

Here is an excellent article about how to use git-filter-repo to modify the commit date. The git-filter-repo documentation explains the concept of --commit-callback pretty well.

A very simple example

Let's reset the timezone of all commit dates to zero.

# Save this as ../change_time.py
def handle(commit):
    "Reset the timezone of all commits."
    date_str = commit.author_date.decode('utf-8')
    [seconds, timezone] = date_str.split()
    new_date = f"{seconds} +0000"
    commit.author_date = new_date.encode('utf-8')

handle(commit)

# You need to be in a freshly-cleaned repo. Or use --force.
git clone <...> your_repo
cd your_repo
# First just a dry run.
git filter-repo --dry-run --commit-callback "$(cat ../change_time.py)"
# And now do it for real
git filter-repo --commit-callback "$(cat ../change_time.py)"
Unapiedra
  • 15,037
  • 12
  • 64
  • 93
  • https://www.git-scm.com/docs/git-filter-branch#_warning is a reference for the "git filter-branch is deprecated" comment. – phils Sep 09 '22 at 00:06
1

git rebase supports the --exec option, which will do exactly that.

-x <cmd>

--exec <cmd>

Append "exec <cmd>" after each line creating a commit in the final history. <cmd> will be interpreted as one or more shell commands. Any command that fails will interrupt the rebase, with exit code 1.

user3840170
  • 26,597
  • 4
  • 30
  • 62
-1

Filter-Repo

In other answer it was suggested to save code to file .py and run it with git filter-repo --commit-callback "$(cat ../<your file name>.py)" but then it ignored in my case all whitespaces which in python breaks syntax. For me worked pasting it directly into command. I am using Windows, tested on PowerShell, beginner in these things.

More advanced example

Set new date for commits based on commits containing given string. But BEWARE, you shouldn't change date unless you have really good reason!

if(b'[structural-programming]' in commit.message):
    base_date = datetime(2021,1,1,0,0,0)
    print(commit.message,' new date: ',base_date)
    commit.committer_date = f'{int(datetime.timestamp(base_date))} +0100'.encode('utf-8')
    commit.author_date = f'{int(datetime.timestamp(base_date))} +0100'.encode('utf-8')
elif(b'[intro-into-programming]' in commit.message):
    base_date = datetime(2021,1,2,0,0,0)
    print(commit.message,' new date: ',base_date)
    commit.committer_date = f'{int(datetime.timestamp(base_date))} +0100'.encode('utf-8')
    commit.author_date = f'{int(datetime.timestamp(base_date))} +0100'.encode('utf-8')
else:
    base_date = datetime(2021,1,3,0,0,0)
    print(commit.message,' new date: ',base_date)
    commit.committer_date = f'{int(datetime.timestamp(base_date))} +0100'.encode('utf-8')
    commit.author_date = f'{int(datetime.timestamp(base_date))} +0100'.encode('utf-8')

and how it is used in console:

git filter-repo --commit-callback "                            
 [seconds, timezone] = commit.committer_date.decode('utf-8').split()
 
 if(b'[structural-programming]' in commit.message):
     base_date = datetime(2021,1,1,0,0,0)
     print(commit.message,' new date: ',base_date)
     commit.committer_date = f'{int(datetime.timestamp(base_date))} +0100'.encode('utf-8')
     commit.author_date = f'{int(datetime.timestamp(base_date))} +0100'.encode('utf-8')
 elif(b'[intro-into-programming]' in commit.message):
     base_date = datetime(2021,1,2,0,0,0)
     print(commit.message,' new date: ',base_date)
     commit.committer_date = f'{int(datetime.timestamp(base_date))} +0100'.encode('utf-8')
     commit.author_date = f'{int(datetime.timestamp(base_date))} +0100'.encode('utf-8')
 else:
     base_date = datetime(2021,1,3,0,0,0)
     print(commit.message,' new date: ',base_date)
     commit.committer_date = f'{int(datetime.timestamp(base_date))} +0100'.encode('utf-8')
     commit.author_date = f'{int(datetime.timestamp(base_date))} +0100'.encode('utf-8')
 "