Useful aliases
alias ll="ls -lah"
alias branch="git branch"
alias checkout="git checkout"
commit() {
echo "Enter commit message (Ctrl+D to finish):"
msg=$(cat)
git commit -m "$msg"
}
add() {
# Ensure git repo
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 0
# Colors
GREEN="\e[32m"
RED="\e[31m"
YELLOW="\e[33m"
CYAN="\e[36m"
BOLD="\e[1m"
RESET="\e[0m"
local current_branch remote_branch behind
local files file answer
local added_files=()
local skipped_files=()
local temp_ignored_files=()
local existing_temp_ignored=()
current_branch=$(git branch --show-current)
# ---------- STEP 0: Check existing temp-ignore files ----------
mapfile -t existing_temp_ignored < <(git ls-files -v | awk '/^S / {print substr($0,3)}')
if [ ${#existing_temp_ignored[@]} -gt 0 ]; then
echo -e "${YELLOW}⚠ There are temporarily ignored (skip-worktree) files:${RESET}"
printf ' - %s\n' "${existing_temp_ignored[@]}"
echo
printf "${BOLD}Continue staging anyway?${RESET} [${GREEN}Y${RESET}=yes, ${RED}N${RESET}=no]: "
read -r answer
case "$answer" in
y|Y)
echo
;;
*)
echo -e "${RED}Staging aborted.${RESET}"
return 0
;;
esac
fi
# ---------- STEP 1: Remote update check ----------
printf "${CYAN}Check updates from which branch?${RESET} [default: %s]: " "origin/$current_branch"
read -r input_branch
if [ -z "$input_branch" ]; then
remote_branch="origin/$current_branch"
else
remote_branch="origin/$input_branch"
fi
echo "Fetching latest refs..."
git fetch >/dev/null 2>&1 || {
echo -e "${RED}Fetch failed.${RESET}"
return 1
}
behind=$(git rev-list --count HEAD.."$remote_branch" 2>/dev/null)
if [ -z "$behind" ]; then
echo -e "${RED}Branch '$remote_branch' not found.${RESET}"
return 1
fi
if [ "$behind" -gt 0 ]; then
echo -e "${RED}✖ $remote_branch has $behind new commit(s).${RESET}"
echo -e "${YELLOW}Staging is blocked to prevent conflicts.${RESET}"
echo
cat <<EOF
Suggested actions:
git merge $remote_branch (preserves history)
# or
git rebase $remote_branch (rewrites history)
EOF
echo
echo -e "${BOLD}Resolve updates first, then re-run staging.${RESET}"
return 1
fi
echo -e "${GREEN}✔ No updates in $remote_branch. Continuing to staging.${RESET}"
# ---------- STEP 2: Interactive staging ----------
files=$(git status --porcelain | awk '{print $2}')
if [ -z "$files" ]; then
echo -e "${YELLOW}No modified files to stage.${RESET}"
return 0
fi
for file in $files; do
while true; do
printf "${BOLD}Add '${file}'?${RESET} [${GREEN}y${RESET}=yes, ${RED}n${RESET}=no, ${YELLOW}d${RESET}=diff, ${CYAN}t${RESET}=temp-ignore]: "
read -r answer
case "$answer" in
y|Y)
git add -- "$file"
added_files+=("$file")
break
;;
n|N)
skipped_files+=("$file")
break
;;
d|D)
echo -e "${YELLOW}--- Diff for $file ---${RESET}"
git diff -- "$file"
echo -e "${YELLOW}----------------------${RESET}"
;;
t|T)
if git ls-files -v -- "$file" | grep -q '^S'; then
echo -e "${YELLOW}Already temporarily ignored.${RESET}"
else
git update-index --skip-worktree -- "$file"
echo -e "${CYAN}Temporarily ignored (skip-worktree).${RESET}"
fi
temp_ignored_files+=("$file")
break
;;
*)
echo -e "${RED}Invalid input, choose y, n, d, or t.${RESET}"
;;
esac
done
done
# ---------- STEP 3: Summary ----------
echo -e "\n${GREEN}Added files:${RESET}"
[ ${#added_files[@]} -eq 0 ] && echo "(None)" || printf '%s\n' "${added_files[@]}"
echo -e "\n${RED}Skipped files:${RESET}"
[ ${#skipped_files[@]} -eq 0 ] && echo "(None)" || printf '%s\n' "${skipped_files[@]}"
echo -e "\n${CYAN}Temporarily ignored (skip-worktree):${RESET}"
[ ${#temp_ignored_files[@]} -eq 0 ] && echo "(None)" || printf '%s\n' "${temp_ignored_files[@]}"
echo -e "\n${YELLOW}Done.${RESET}"
}
git_push() {
# Colors
RED="\033[0;31m"
GREEN="\033[0;32m"
CYAN="\033[0;36m"
YELLOW="\033[1;33m"
NC="\033[0m"
CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
git fetch origin "$CURRENT_BRANCH" >/dev/null 2>&1
echo -e "${CYAN}Commits to push on $CURRENT_BRANCH:${NC}"
git log origin/$CURRENT_BRANCH..$CURRENT_BRANCH --oneline || echo "No upstream set yet."
echo
BEHIND_COUNT=$(git rev-list --count $CURRENT_BRANCH..origin/$CURRENT_BRANCH 2>/dev/null || echo 0)
if [ "$BEHIND_COUNT" -gt 0 ]; then
echo -e "${YELLOW}⚠ Your branch is behind origin by $BEHIND_COUNT commit(s).${NC}"
read -p "Auto rebase with 'git pull --rebase'? (Y/n): " REBASE_CONF
REBASE_CONF=${REBASE_CONF:-Y}
if [[ "$REBASE_CONF" =~ ^[Yy]$ ]]; then
echo -e "${CYAN}Rebasing...${NC}"
if ! git pull --rebase origin "$CURRENT_BRANCH"; then
echo -e "${RED}❌ Rebase failed. Resolve conflicts and retry.${NC}"
return 1
fi
else
echo -e "${RED}Push cancelled because branch is behind.${NC}"
return 1
fi
fi
if [[ "$CURRENT_BRANCH" == "main" || "$CURRENT_BRANCH" == "master" ]]; then
echo -e "${RED}⚠ You are on ${CURRENT_BRANCH}. Be careful!${NC}"
read -p "Type YES to confirm push: " CONFIRM
if [[ "$CONFIRM" != "YES" ]]; then
echo -e "${YELLOW}Push cancelled.${NC}"
return 1
fi
fi
printf "Enter remote branch name (or press Enter to use %s): " "$CURRENT_BRANCH"
read USER_BRANCH
if [ -z "$USER_BRANCH" ]; then USER_BRANCH="$CURRENT_BRANCH"; fi
echo -e "${GREEN}Pushing to origin/$USER_BRANCH ...${NC}"
if git push -u origin "$CURRENT_BRANCH":"$USER_BRANCH"; then
echo
echo -e "${GREEN}✔ Push successful!${NC}"
echo -e "${CYAN}📝 Summary of pushed commits:${NC}"
# Show commits that just got pushed
git log origin/$USER_BRANCH --oneline --no-decorate | head -n 10
echo -e "${YELLOW}(showing latest up to 10 commits)${NC}"
echo
echo -e "${GREEN}Remote branch: origin/$USER_BRANCH${NC}"
else
echo -e "${RED}❌ Push failed.${NC}"
return 1
fi
}
alias push="git_push"
unstaged() {
local files
files=$(git diff --cached --name-only)
if [ -z "$files" ]; then
echo -e "\e[33mNo staged files.\e[0m"
return 0
fi
# Colors
GREEN="\e[32m"
RED="\e[31m"
YELLOW="\e[33m"
CYAN="\e[36m"
BOLD="\e[1m"
RESET="\e[0m"
echo -e "${BOLD}Staged files:${RESET}"
echo "----------------"
while IFS= read -r file; do
echo
echo -e "${CYAN}File:${RESET} ${BOLD}$file${RESET}"
echo -e "${YELLOW}--- Staged diff ---${RESET}"
git diff --cached -- "$file"
echo
printf "${BOLD}Action${RESET} [${GREEN}y${RESET}=unstage, ${RED}n${RESET}=skip, ${CYAN}a${RESET}=unstage ALL]: "
read -r answer
case "$answer" in
y|Y)
git restore --staged "$file"
echo -e "${GREEN}✔ Unstaged:${RESET} $file"
;;
a|A)
git restore --staged .
echo -e "${RED}✔ All files unstaged.${RESET}"
return 0
;;
*)
echo -e "${YELLOW}⏭ Skipped:${RESET} $file"
;;
esac
done <<< "$files"
echo
echo -e "${BOLD}Done.${RESET}"
}
untemp() {
# Ensure git repo
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || {
echo "Not a git repository."
return 1
}
# Collect skip-worktree files
mapfile -t files < <(git ls-files -v | awk '/^S / {print substr($0,3)}')
if [ ${#files[@]} -eq 0 ]; then
echo "No temporarily ignored (skip-worktree) files found."
return 0
fi
echo "Removing temp-ignore (skip-worktree) from:"
for file in "${files[@]}"; do
echo " - $file"
git update-index --no-skip-worktree -- "$file"
done
echo
echo "Restored files:"
printf '%s\n' "${files[@]}"
}
Total page views:
Comments
Post a Comment