diff --git a/AUTHORS b/AUTHORS index c902cd0a2..a00870310 100644 --- a/AUTHORS +++ b/AUTHORS @@ -270,6 +270,7 @@ Patches and Suggestions - sgleizes - tfendin - tiemonl +- Zachary Miller - zentarul - zeroDivisible - zhiyanfoo diff --git a/Commands.md b/Commands.md index 3335df6b3..af72af09e 100644 --- a/Commands.md +++ b/Commands.md @@ -52,6 +52,7 @@ - [`git rebase-patch`](#git-rebase-patch) - [`git release`](#git-release) - [`git rename-branch`](#git-rename-branch) + - [`git rename-file`](#git-rename-file) - [`git rename-tag`](#git-rename-tag) - [`git rename-remote`](#git-rename-remote) - [`git repl`](#git-repl) @@ -559,6 +560,20 @@ $ git rename-branch old-name new-name $ git rename-branch new-name ``` +## git rename-file + +Rename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity. +It combines the functionality of the `mv` command and `git mv`. This is particularly useful for renaming files or directories +to change only their case, which might not be detected by Git on case-insensitive filesystems. + +```bash +# Rename a file +git rename-file old_filename new_filename + +# Rename a directory +git rename-file old_directory new_directory +``` + ## git rename-tag Rename a tag (locally and remotely). diff --git a/bin/git-rename-file b/bin/git-rename-file new file mode 100755 index 000000000..093f8c2c9 --- /dev/null +++ b/bin/git-rename-file @@ -0,0 +1,101 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Usage function +usage() { + cat < + +Description: + Rename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity. + It combines the functionality of the "mv" command and "git mv". This is particularly useful for renaming files or directories + to change only their case, which might not be detected by Git on case-insensitive filesystems. + +Options: + -h, --help Show this help message and exit. + +Examples: + git rename-file old_filename new_filename + git rename-file old_directory new_directory +EOF +} + +# Check for help option +if [[ "$1" == "-h" || "$1" == "--help" ]]; then + usage + exit 0 +fi + +# Check for correct number of arguments +if [ "$#" -ne 2 ]; then + echo "Error: Incorrect number of arguments." + echo "" + usage >&2 + exit 1 +fi + +# Assign variables +SOURCE="$1" +DESTINATION="$2" +TEMP_NAME="${SOURCE}.temp" + +# Function to check if a file or directory exists in a case-sensitive manner +check_case_sensitive_exists() { + local path="$1" + local dir + local base + + dir=$(dirname "$path") + base=$(basename "$path") + + if [ -e "$dir" ]; then + if (cd "$dir" && find . -maxdepth 1 -name "$base" | grep -q "$base"); then + return 0 + fi + fi + return 1 +} + +# Check if source exists and is under version control +if ! check_case_sensitive_exists "$SOURCE"; then + echo "Error: Source '$SOURCE' does not exist." + exit 1 +fi + +if ! git ls-files --error-unmatch "$SOURCE" > /dev/null 2>&1; then + echo "Error: Source '$SOURCE' is not under version control. If file or directory is new, it must at least be staged." + exit 1 +fi + +# Check if destination already exists +if check_case_sensitive_exists "$DESTINATION"; then + echo "Error: Destination '$DESTINATION' already exists." + exit 1 +fi + +# Check if the destination directory exists +DEST_DIR=$(dirname "$DESTINATION") +if ! check_case_sensitive_exists "$DEST_DIR"; then + echo "Error: Destination directory '$DEST_DIR' does not exist." + exit 1 +fi + +# Create a rollback function +rollback() { + echo "Rolling back changes..." + if [ -e "$TEMP_NAME" ]; then + git mv -f "$TEMP_NAME" "$SOURCE" + fi +} + +# Trap errors to trigger rollback +trap 'rollback' ERR + +# Move the file to a temporary name within the Git repository +git mv "$SOURCE" "$TEMP_NAME" + +# Move the temporary file to the desired destination +git mv "$TEMP_NAME" "$DESTINATION" + +echo "Successfully renamed '$SOURCE' to '$DESTINATION'." diff --git a/etc/bash_completion.sh b/etc/bash_completion.sh index 3fc1dcc21..7a6360a59 100644 --- a/etc/bash_completion.sh +++ b/etc/bash_completion.sh @@ -189,3 +189,7 @@ _git_browse(){ _git_browse_ci(){ __git_complete_remote_or_refspec } + +_git_rename_file() { + __gitcomp "-h --help" +} diff --git a/etc/git-extras-completion.zsh b/etc/git-extras-completion.zsh index a5cbd570e..3a44d6b88 100644 --- a/etc/git-extras-completion.zsh +++ b/etc/git-extras-completion.zsh @@ -316,6 +316,14 @@ _git-release() { '--[The arguments listed after "--" separator will be passed to pre/post-release hook.]' } +_git-rename-file() { + _arguments -C \ + '-h[show usage information]' \ + '--help[show usage information]' \ + '1:source:__git_files' \ + '2:destination:__git_files' +} + _git-squash() { _arguments '--squash-msg[commit with the squashed commit messages]' _arguments \ @@ -411,6 +419,7 @@ zstyle ':completion:*:*:git:*' user-commands $existing_user_commands \ refactor:'create refactor branch' \ release:'commit, tag and push changes to the repository' \ rename-branch:'rename a branch' \ + rename-file:'rename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity' \ rename-tag:'rename a tag' \ rename-remote:'rename a remote' \ repl:'git read-eval-print-loop' \ diff --git a/etc/git-extras.fish b/etc/git-extras.fish index b971fc119..0de358f55 100644 --- a/etc/git-extras.fish +++ b/etc/git-extras.fish @@ -50,6 +50,7 @@ set __fish_git_extras_commands \ "rebase-patch:Rebases a patch" \ "release:Commit, tag and push changes to the repository" \ "rename-branch:rename local branch and push to remote" \ + "rename-file:rename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity" \ "rename-remote:Rename a remote" \ "rename-tag:Rename a tag" \ "repl:git read-eval-print-loop" \ @@ -180,6 +181,8 @@ complete -c git -n '__fish_git_using_command merge-into' -l ff-only -d 'merge on complete -c git -x -n '__fish_git_using_command merge-into' -a '(__fish_git_branches)' # missing complete -c git -x -n '__fish_git_using_command missing' -a '(__fish_git_branches)' +# rename-file +complete -c git -f -n '__fish_git_using_command rename-file' -s h -l help -d 'Show usage information' # squash complete -c git -x -n '__fish_git_using_command squash' -a '(__fish_git_branches)' complete -c git -x -n '__fish_git_using_command squash' -l squash-msg -d 'commit with the squashed commit messages' diff --git a/man/git-extras.md b/man/git-extras.md index 7ee272249..e959748f1 100644 --- a/man/git-extras.md +++ b/man/git-extras.md @@ -79,6 +79,7 @@ git-extras(1) -- Awesome GIT utilities - **git-rebase-patch(1)** Rebases a patch - **git-release(1)** Commit, tag and push changes to the repository - **git-rename-branch(1)** rename local branch and push to remote + - **git-rename-file(1)** CRename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity. - **git-rename-remote(1)** Rename a remote - **git-rename-tag(1)** Rename a tag - **git-repl(1)** git read-eval-print-loop diff --git a/man/git-rename-file.1 b/man/git-rename-file.1 new file mode 100644 index 000000000..4295697bc --- /dev/null +++ b/man/git-rename-file.1 @@ -0,0 +1,30 @@ +.\" generated with Ronn-NG/v0.8.0 +.\" http://github.com/apjanke/ronn-ng/tree/0.8.0 +.TH "GIT\-RENAME\-FILE" "1" "July 2024" "" "Git Extras" +.SH "NAME" +\fBgit\-rename\-file\fR \- Rename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity. +.SH "SYNOPSIS" +\fBgit\-rename\-file\fR [OPTIONS] +.SH "DESCRIPTION" +The \fBgit\-rename\-file\fR command renames a file or directory and ensures Git recognizes the change, regardless of filesystem case-sensitivity. It combines the functionality of the \fBmv\fR command and \fBgit mv\fR. +This is particularly useful for renaming files or directories to change only their case, which might not be detected by Git on case-insensitive filesystems. +.SH "OPTIONS" +\fB\-h\fR, \fB\-\-help\fR +.RS +Show usage information. +.RE +.SH "EXAMPLES" +Rename a file: +.RS +\fBgit\-rename\-file old_filename new_filename\fR +.RE +Rename a directory: +.RS +\fBgit\-rename\-file old_directory new_directory\fR +.RE +.SH "AUTHOR" +Written by Zachary Miller <\fI\%codebyzach@gmail.com\fR> +.SH "REPORTING BUGS" +<\fI\%https://github.com/tj/git-extras/issues\fR> +.SH "SEE ALSO" +<\fI\%https://github.com/tj/git-extras\fR> diff --git a/man/git-rename-file.html b/man/git-rename-file.html new file mode 100644 index 000000000..a7826b9a5 --- /dev/null +++ b/man/git-rename-file.html @@ -0,0 +1,106 @@ + + + + + + git-rename-file(1) - Rename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity. + + + +
+ + + +
    +
  1. git-rename-file(1)
  2. +
  3. Git Extras
  4. +
  5. git-rename-file(1)
  6. +
+ +

NAME

+

+ git-rename-file - Rename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity +

+ +

SYNOPSIS

+

git-rename-file [OPTIONS] <source> <destination>

+ +

DESCRIPTION

+

The git-rename-file command renames a file or directory and ensures Git recognizes the change, regardless of filesystem case-sensitivity. It combines the functionality of the mv command and git mv.

+

This is particularly useful for renaming files or directories to change only their case, which might not be detected by Git on case-insensitive filesystems.

+ +

OPTIONS

+
+
-h, --help
+
Show usage information.
+
+ +

EXAMPLES

+

Rename a file:

+
git-rename-file old_filename new_filename
+

Rename a directory:

+
git-rename-file old_directory new_directory
+ +

AUTHOR

+

Written by <Zachary Miller> <codebyzach@gmail.com>

+ +

REPORTING BUGS

+

<https://github.com/tj/git-extras/issues>

+ +

SEE ALSO

+

<https://github.com/tj/git-extras>

+ +
    +
  1. +
  2. July 2024
  3. +
  4. git-rename-file(1)
  5. +
+ +
+ + diff --git a/man/git-rename-file.md b/man/git-rename-file.md new file mode 100644 index 000000000..2576f3fba --- /dev/null +++ b/man/git-rename-file.md @@ -0,0 +1,43 @@ +git-rename-file(1) -- Rename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity. +================================================ + +## SYNOPSIS + +`git-rename-file` [OPTIONS] + +## DESCRIPTION + +The `git-rename-file` command renames a file or directory and ensures Git recognizes the change, regardless of filesystem case-sensitivity. It combines the functionality of the `mv` command and `git mv`. + +This is particularly useful for renaming files or directories to change only their case, which might not be detected by Git on case-insensitive filesystems. + +## OPTIONS + +-h, --help + Show usage information. + +## EXAMPLES + +Rename a file: + +```sh +git-rename-file old_filename new_filename +``` + +Rename a directory: + +```sh +git-rename-file old_directory new_directory +``` + +## AUTHOR + +Written by Zachary Miller <> + +## REPORTING BUGS + + + +## SEE ALSO + + diff --git a/man/index.txt b/man/index.txt index f54005e5b..21c65034d 100644 --- a/man/index.txt +++ b/man/index.txt @@ -52,6 +52,7 @@ git-reauthor(1) git-reauthor git-rebase-patch(1) git-rebase-patch git-release(1) git-release git-rename-branch(1) git-rename-branch +git-rename-file(1) git-rename-file git-rename-remote(1) git-rename-remote git-rename-tag(1) git-rename-tag git-repl(1) git-repl