In git, there are no renames. It uses "heuristics" to detect files been deleted-and-added that are "actually" renamed. The "good practice" is to never mix these "renames" with file modifications, else git will loose the track of "renames" and thus history navigation for these files will become a serious pain. But sometimes you "forget" about these "great" practices. The script to fix an accidental loss of real rename below is to the resque.
#!/bin/bash # Check if all required arguments are provided if [ $# -ne 4 ]; then echo "Usage: $0" exit 1 fi REPO_PATH="$1" COMMIT_HASH="$2" OLD_FILE="$3" NEW_FILE="$4" # Change to the repository directory cd "$REPO_PATH" || exit 1 # Verify if the commit exists if ! git rev-parse --quiet --verify "$COMMIT_HASH^{commit}" >/dev/null; then echo "Error: Commit $COMMIT_HASH does not exist" exit 1 fi # Stash any untracked files git stash push --include-untracked --message "Stashing untracked files before rebase" # Get the hash of the commit following the target commit NEXT_COMMIT_HASH=$(git rev-list --topo-order --reverse "$COMMIT_HASH"..HEAD | head -1) # Memorize the "new state" of the added file in the target commit git show "$COMMIT_HASH:$NEW_FILE" > temp_new_file # Use GIT_SEQUENCE_EDITOR to modify the rebase todo list non-interactively export GIT_SEQUENCE_EDITOR="sed -i '1s/^pick/edit/'" # Start the rebase process git rebase -i "$COMMIT_HASH^" # Remove the new file and add the old file to simulate rename git rm "$NEW_FILE" git show "$COMMIT_HASH^:$OLD_FILE" > "$OLD_FILE" git add -f "$OLD_FILE" # Perform the rename git mv "$OLD_FILE" "$NEW_FILE" # Amend the commit without changing the commit message or author date git commit --amend --no-edit --date="$(git show -s --format=%aI $COMMIT_HASH)" # Get the author date of the target commit TARGET_DATE=$(git show -s --format=%ai "$COMMIT_HASH") echo "Target commit author date: $TARGET_DATE" # Get the author date of the commit following the target commit NEXT_DATE=$(git show -s --format=%ai "$NEXT_COMMIT_HASH") echo "Next commit author date: $NEXT_DATE" # Calculate the middle date between the target commit and the next commit MIDDLE_DATE=$(date -d "$TARGET_DATE +$((($(date -d "$NEXT_DATE" +%s) - $(date -d "$TARGET_DATE" +%s)) / 2)) seconds" +"%Y-%m-%d %H:%M:%S %z") echo "Middle date: $MIDDLE_DATE" # Create a new commit following right after the target commit with the middle date mv temp_new_file "$NEW_FILE" git add "$NEW_FILE" GIT_AUTHOR_DATE="$MIDDLE_DATE" GIT_COMMITTER_DATE="$MIDDLE_DATE" git commit -m "Update content of $NEW_FILE" # Continue the rebase with preserved author dates git -c rebase.instructionFormat='%s%nexec GIT_COMMITTER_DATE="$(git show -s --format=%aI)" git commit --amend --no-edit --date="$(git show -s --format=%aI)"' rebase --continue # Restore the stashed untracked files git stash pop # Clean up rm -f temp_new_file echo "Operation completed successfully."
🤡
No comments:
Post a Comment