Skip to content

Commit c32869d

Browse files
authored
feat: add rename-file command (#1149)
1 parent e1a4e71 commit c32869d

11 files changed

+314
-0
lines changed

AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ Patches and Suggestions
270270
- sgleizes
271271
- tfendin
272272
- tiemonl
273+
- Zachary Miller
273274
- zentarul
274275
- zeroDivisible
275276
- zhiyanfoo

Commands.md

+15
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
- [`git rebase-patch`](#git-rebase-patch)
5353
- [`git release`](#git-release)
5454
- [`git rename-branch`](#git-rename-branch)
55+
- [`git rename-file`](#git-rename-file)
5556
- [`git rename-tag`](#git-rename-tag)
5657
- [`git rename-remote`](#git-rename-remote)
5758
- [`git repl`](#git-repl)
@@ -559,6 +560,20 @@ $ git rename-branch old-name new-name
559560
$ git rename-branch new-name
560561
```
561562

563+
## git rename-file
564+
565+
Rename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity.
566+
It combines the functionality of the `mv` command and `git mv`. This is particularly useful for renaming files or directories
567+
to change only their case, which might not be detected by Git on case-insensitive filesystems.
568+
569+
```bash
570+
# Rename a file
571+
git rename-file old_filename new_filename
572+
573+
# Rename a directory
574+
git rename-file old_directory new_directory
575+
```
576+
562577
## git rename-tag
563578

564579
Rename a tag (locally and remotely).

bin/git-rename-file

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
# Usage function
6+
usage() {
7+
cat <<EOF
8+
Usage: git rename-file [OPTIONS] <source> <destination>
9+
10+
Description:
11+
Rename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity.
12+
It combines the functionality of the "mv" command and "git mv". This is particularly useful for renaming files or directories
13+
to change only their case, which might not be detected by Git on case-insensitive filesystems.
14+
15+
Options:
16+
-h, --help Show this help message and exit.
17+
18+
Examples:
19+
git rename-file old_filename new_filename
20+
git rename-file old_directory new_directory
21+
EOF
22+
}
23+
24+
# Check for help option
25+
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
26+
usage
27+
exit 0
28+
fi
29+
30+
# Check for correct number of arguments
31+
if [ "$#" -ne 2 ]; then
32+
echo "Error: Incorrect number of arguments."
33+
echo ""
34+
usage >&2
35+
exit 1
36+
fi
37+
38+
# Assign variables
39+
SOURCE="$1"
40+
DESTINATION="$2"
41+
TEMP_NAME="${SOURCE}.temp"
42+
43+
# Function to check if a file or directory exists in a case-sensitive manner
44+
check_case_sensitive_exists() {
45+
local path="$1"
46+
local dir
47+
local base
48+
49+
dir=$(dirname "$path")
50+
base=$(basename "$path")
51+
52+
if [ -e "$dir" ]; then
53+
if (cd "$dir" && find . -maxdepth 1 -name "$base" | grep -q "$base"); then
54+
return 0
55+
fi
56+
fi
57+
return 1
58+
}
59+
60+
# Check if source exists and is under version control
61+
if ! check_case_sensitive_exists "$SOURCE"; then
62+
echo "Error: Source '$SOURCE' does not exist."
63+
exit 1
64+
fi
65+
66+
if ! git ls-files --error-unmatch "$SOURCE" > /dev/null 2>&1; then
67+
echo "Error: Source '$SOURCE' is not under version control. If file or directory is new, it must at least be staged."
68+
exit 1
69+
fi
70+
71+
# Check if destination already exists
72+
if check_case_sensitive_exists "$DESTINATION"; then
73+
echo "Error: Destination '$DESTINATION' already exists."
74+
exit 1
75+
fi
76+
77+
# Check if the destination directory exists
78+
DEST_DIR=$(dirname "$DESTINATION")
79+
if ! check_case_sensitive_exists "$DEST_DIR"; then
80+
echo "Error: Destination directory '$DEST_DIR' does not exist."
81+
exit 1
82+
fi
83+
84+
# Create a rollback function
85+
rollback() {
86+
echo "Rolling back changes..."
87+
if [ -e "$TEMP_NAME" ]; then
88+
git mv -f "$TEMP_NAME" "$SOURCE"
89+
fi
90+
}
91+
92+
# Trap errors to trigger rollback
93+
trap 'rollback' ERR
94+
95+
# Move the file to a temporary name within the Git repository
96+
git mv "$SOURCE" "$TEMP_NAME"
97+
98+
# Move the temporary file to the desired destination
99+
git mv "$TEMP_NAME" "$DESTINATION"
100+
101+
echo "Successfully renamed '$SOURCE' to '$DESTINATION'."

etc/bash_completion.sh

+4
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,7 @@ _git_browse(){
189189
_git_browse_ci(){
190190
__git_complete_remote_or_refspec
191191
}
192+
193+
_git_rename_file() {
194+
__gitcomp "-h --help"
195+
}

etc/git-extras-completion.zsh

+9
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,14 @@ _git-release() {
316316
'--[The arguments listed after "--" separator will be passed to pre/post-release hook.]'
317317
}
318318

319+
_git-rename-file() {
320+
_arguments -C \
321+
'-h[show usage information]' \
322+
'--help[show usage information]' \
323+
'1:source:__git_files' \
324+
'2:destination:__git_files'
325+
}
326+
319327
_git-squash() {
320328
_arguments '--squash-msg[commit with the squashed commit messages]'
321329
_arguments \
@@ -411,6 +419,7 @@ zstyle ':completion:*:*:git:*' user-commands $existing_user_commands \
411419
refactor:'create refactor branch' \
412420
release:'commit, tag and push changes to the repository' \
413421
rename-branch:'rename a branch' \
422+
rename-file:'rename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity' \
414423
rename-tag:'rename a tag' \
415424
rename-remote:'rename a remote' \
416425
repl:'git read-eval-print-loop' \

etc/git-extras.fish

+3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ set __fish_git_extras_commands \
5050
"rebase-patch:Rebases a patch" \
5151
"release:Commit, tag and push changes to the repository" \
5252
"rename-branch:rename local branch and push to remote" \
53+
"rename-file:rename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity" \
5354
"rename-remote:Rename a remote" \
5455
"rename-tag:Rename a tag" \
5556
"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
180181
complete -c git -x -n '__fish_git_using_command merge-into' -a '(__fish_git_branches)'
181182
# missing
182183
complete -c git -x -n '__fish_git_using_command missing' -a '(__fish_git_branches)'
184+
# rename-file
185+
complete -c git -f -n '__fish_git_using_command rename-file' -s h -l help -d 'Show usage information'
183186
# squash
184187
complete -c git -x -n '__fish_git_using_command squash' -a '(__fish_git_branches)'
185188
complete -c git -x -n '__fish_git_using_command squash' -l squash-msg -d 'commit with the squashed commit messages'

man/git-extras.md

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ git-extras(1) -- Awesome GIT utilities
7979
- **git-rebase-patch(1)** Rebases a patch
8080
- **git-release(1)** Commit, tag and push changes to the repository
8181
- **git-rename-branch(1)** rename local branch and push to remote
82+
- **git-rename-file(1)** CRename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity.
8283
- **git-rename-remote(1)** Rename a remote
8384
- **git-rename-tag(1)** Rename a tag
8485
- **git-repl(1)** git read-eval-print-loop

man/git-rename-file.1

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
.\" generated with Ronn-NG/v0.8.0
2+
.\" http://github.com/apjanke/ronn-ng/tree/0.8.0
3+
.TH "GIT\-RENAME\-FILE" "1" "July 2024" "" "Git Extras"
4+
.SH "NAME"
5+
\fBgit\-rename\-file\fR \- Rename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity.
6+
.SH "SYNOPSIS"
7+
\fBgit\-rename\-file\fR [OPTIONS] <source> <destination>
8+
.SH "DESCRIPTION"
9+
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.
10+
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.
11+
.SH "OPTIONS"
12+
\fB\-h\fR, \fB\-\-help\fR
13+
.RS
14+
Show usage information.
15+
.RE
16+
.SH "EXAMPLES"
17+
Rename a file:
18+
.RS
19+
\fBgit\-rename\-file old_filename new_filename\fR
20+
.RE
21+
Rename a directory:
22+
.RS
23+
\fBgit\-rename\-file old_directory new_directory\fR
24+
.RE
25+
.SH "AUTHOR"
26+
Written by Zachary Miller <\fI\%codebyzach@gmail.com\fR>
27+
.SH "REPORTING BUGS"
28+
<\fI\%https://github.com/tj/git-extras/issues\fR>
29+
.SH "SEE ALSO"
30+
<\fI\%https://github.com/tj/git-extras\fR>

man/git-rename-file.html

+106
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/git-rename-file.md

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
git-rename-file(1) -- Rename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity.
2+
================================================
3+
4+
## SYNOPSIS
5+
6+
`git-rename-file` [OPTIONS] <source> <destination>
7+
8+
## DESCRIPTION
9+
10+
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`.
11+
12+
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.
13+
14+
## OPTIONS
15+
16+
-h, --help
17+
Show usage information.
18+
19+
## EXAMPLES
20+
21+
Rename a file:
22+
23+
```sh
24+
git-rename-file old_filename new_filename
25+
```
26+
27+
Rename a directory:
28+
29+
```sh
30+
git-rename-file old_directory new_directory
31+
```
32+
33+
## AUTHOR
34+
35+
Written by Zachary Miller &lt;<codebyzach@gmail.com>&gt;
36+
37+
## REPORTING BUGS
38+
39+
<https://github.com/tj/git-extras/issues>
40+
41+
## SEE ALSO
42+
43+
<https://github.com/tj/git-extras>

man/index.txt

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ git-reauthor(1) git-reauthor
5252
git-rebase-patch(1) git-rebase-patch
5353
git-release(1) git-release
5454
git-rename-branch(1) git-rename-branch
55+
git-rename-file(1) git-rename-file
5556
git-rename-remote(1) git-rename-remote
5657
git-rename-tag(1) git-rename-tag
5758
git-repl(1) git-repl

0 commit comments

Comments
 (0)