Git(读音为/gɪt/)是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。 也是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源码的版本控制软件。

安装完 Git 之后,要做的第一件事就是

安装后

git配置

设置你的用户名和邮件地址。 这一点很重要,因为每一个 Git 提交都会使用这些信息,它们会写入到你的每一次提交中,:

git config user.name "liupei"
git config user.email "cumtlp@qq.com"
git config --global core.editor "vim"

检查配置信息

git config --list

获取帮助

git help <verb>

如要获取 git config 命令手册,执行

git help config

建立git仓库

从本地目录初始化

git init 仓库名
git add .
git commit -m 'initial project version'

从远程克隆仓库

克隆仓库的命令是 git clone <url> 。 比如,要克隆 Git 的链接库 libgit2,可以用下面的命令:

git clone https://github.com/libgit2/libgit2

如果你想在克隆远程仓库的时候,自定义本地仓库的名字,你可以通过额外的参数指定新的目录名:

git clone https://github.com/libgit2/libgit2 mylibgit

克隆指定分支

git clone -b mfiles ssh://username@ip:135/var/repo/web_blog blog

批量迁移仓库

需求分析:

  • 从远程服务器(比如某台云服务器)下载多个 Git 仓库到你的本地电脑上
  • 新服务器是你本地电脑,不能通过 SSH 被主动访问;
  • 所以迁移动作应该在本地电脑发起,用 ssh 从旧服务器拉取仓库数据。

✅ 解决方案

我们将:

  1. 本地电脑上执行一个批量脚本
  2. 利用 ssh + git clone --mirror 从远程服务器拉取仓库;
  3. 在本地生成一组镜像仓库(.git 目录,可继续作为远程仓库使用);

🛠️ 脚本版本:从远程服务器拉取多个 Git 仓库到本地

#!/bin/bash

# 远程仓库信息
REMOTE_USER="user"
REMOTE_HOST="oldserver.com"
REMOTE_REPO_DIR="/home/user/repos"  # 远程仓库所在目录

# 本地存储位置
LOCAL_BACKUP_DIR="$HOME/git_backup_mirror"

# 仓库名列表(不带.git后缀)
REPOS=(
  project1
  project2
  project3
  another_project
)

# 创建本地备份目录
mkdir -p "$LOCAL_BACKUP_DIR"

# 遍历仓库列表
for repo in "${REPOS[@]}"; do
    echo "🔄 备份仓库:$repo"

    LOCAL_REPO_PATH="$LOCAL_BACKUP_DIR/${repo}.git"
    REMOTE_REPO_PATH="$REMOTE_REPO_DIR/$repo"

    # 拉取镜像仓库到本地
    echo "📦 正在镜像 clone $REMOTE_REPO_PATH 到本地 $LOCAL_REPO_PATH"
    git clone --mirror "ssh://${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_REPO_PATH}" "$LOCAL_REPO_PATH"

    if [ $? -eq 0 ]; then
        echo "✅ $repo 迁移完成。"
    else
        echo "❌ $repo 迁移失败,请检查路径或权限。"
    fi

    echo "--------------------------"
done

echo "🎉 所有仓库迁移操作完成,备份目录:$LOCAL_BACKUP_DIR"

✅ 如何使用

1. 修改配置项:

  • REMOTE_USER 改成远程服务器用户名;
  • REMOTE_HOST 改成远程服务器地址(IP 或域名);
  • REMOTE_REPO_DIR 是远程仓库路径;
  • REPOS 是你要迁移的仓库名数组(不带 .git 后缀);
  • LOCAL_BACKUP_DIR 是你本地用于保存仓库的位置。

2. 本地执行脚本:

chmod +x migrate_from_remote.sh
./migrate_from_remote.sh

3. 完整代码

#!/bin/bash

# 远程仓库信息
REMOTE_USER="git"
REMOTE_HOST="xyz.com"
REMOTE_REPO_DIR="/home/git/"  # 远程仓库所在目录

# 本地存储位置
LOCAL_BACKUP_DIR="$HOME/git_backup_mirror"

# 仓库名列表(不带.git后缀)
REPOS=(
  aliRead
  bin
  hexo/hexo
  lxy_scratch
  manuscript/sanyaEro
  manuscript/ttPredict
  xsPaper
)

# ====== 启动备份 ======
echo "📦 开始 Git 仓库备份..."

# 遍历仓库列表
for repo in "${REPOS[@]}"; do
    echo "🔄 备份仓库:$repo"

    REMOTE_REPO_PATH="$REMOTE_REPO_DIR/$repo"
    LOCAL_REPO_PATH="$LOCAL_BACKUP_DIR/${repo}.git"

    # 确保本地父目录存在
    mkdir -p "$(dirname "$LOCAL_REPO_PATH")"

    if [ -d "$LOCAL_REPO_PATH" ]; then
        echo "📥 本地仓库已存在,执行 git remote update"
        cd "$LOCAL_REPO_PATH" && git remote update
    else
        echo "📦 首次 clone 仓库到本地:$LOCAL_REPO_PATH"
        git clone --mirror "ssh://${REMOTE_USER}@${REMOTE_HOST}:22/${REMOTE_REPO_PATH}" "$LOCAL_REPO_PATH"
    fi

    # 拉取镜像仓库到本地
    # echo "📦 正在镜像 clone $REMOTE_REPO_PATH 到本地 $LOCAL_REPO_PATH"
    # git clone --mirror "ssh://${REMOTE_USER}@${REMOTE_HOST}:13579/${REMOTE_REPO_PATH}" "$LOCAL_REPO_PATH"
    #rsync -avz -e "ssh://${REMOTE_USER}@${REMOTE_HOST}:13579/${REMOTE_REPO_PATH}" "$LOCAL_REPO_PATH"

    if [ $? -eq 0 ]; then
        echo "✅ $repo 同步成功。"
    else
        echo "❌ $repo 同步失败,请检查路径或权限。"
    fi

    echo "--------------------------"
done

echo "🎉 所有仓库同步完成,保存在目录:$LOCAL_BACKUP_DIR"

crontab 自动备份

  • 添加定时任务(每天凌晨 2 点执行):
0 2 * * * /home/peter/scripts/backup_git_repos.sh >> /home/yourname/backup_git.log 2>&1

✅ 结果

你会在 $HOME/git_backup_mirror/ 下看到多个 .git 镜像仓库,结构如下:

~/git_backup_mirror/
├── project1.git/
├── project2.git/
├── another_project.git/
└── ...

你可以:

  • 直接用它们初始化本地工作副本:

    git clone ~/git_backup_mirror/project1.git
    
  • 也可以把这些仓库作为远程仓库部署到本地服务器,比如 Gitolite、Gitea、GitLab 等。

批量迁移+增量更新等

定时任务 + 自动扫描远程目录所有 Git 仓库 + 本地镜像备份 + 自动增量更新。不需要手动列出仓库列表,适合持续长期备份。

✅ 目标回顾

你希望:

  1. 从本地电脑(不可公网访问)通过 SSH(含端口)连接远程服务器;
  2. 自动扫描远程仓库目录(含多级子目录);
  3. 本地以 --mirror 方式首次拉取;
  4. 之后每次定时运行,只增量更新已有仓库;
  5. 通过 crontab 实现定期自动执行。

✅ 一、前提设置

远程信息(你可以根据实际修改):

REMOTE_USER="user"
REMOTE_HOST="your.remote.com"
SSH_PORT=2222
REMOTE_REPO_BASE="/home/user/repos"  # 仓库根目录

本地目录:

LOCAL_BACKUP_DIR="$HOME/git_backup_mirror"

✅ 二、自动扫描 + 同步备份脚本

保存为:~/scripts/auto_git_mirror_backup.sh

#!/bin/bash

# ======== 配置 =========
REMOTE_USER="user"
REMOTE_HOST="your.remote.com"
SSH_PORT=2222
REMOTE_REPO_BASE="/home/user/repos"
LOCAL_BACKUP_DIR="$HOME/git_backup_mirror"

# ======== 创建本地目录 ========
mkdir -p "$LOCAL_BACKUP_DIR"

# ======== 从远程扫描所有仓库 ========
echo "🔍 获取远程仓库列表..."
REPO_LIST=$(ssh -p $SSH_PORT ${REMOTE_USER}@${REMOTE_HOST} "find ${REMOTE_REPO_BASE} -type d -name '*.git'")

if [ -z "$REPO_LIST" ]; then
    echo "⚠️ 没有找到任何远程 Git 仓库,结束。"
    exit 1
fi

# ======== 逐个同步仓库 ========
echo "🔄 开始同步仓库..."
while read -r REMOTE_REPO_PATH; do
    # 相对路径
    REL_PATH=${REMOTE_REPO_PATH#${REMOTE_REPO_BASE}/}
    LOCAL_REPO_PATH="${LOCAL_BACKUP_DIR}/${REL_PATH}"

    echo "📦 同步仓库:$REL_PATH"
    mkdir -p "$(dirname "$LOCAL_REPO_PATH")"

    if [ -d "$LOCAL_REPO_PATH" ]; then
        echo "📥 本地已存在,执行 remote update"
        cd "$LOCAL_REPO_PATH" && git remote update
    else
        echo "🚀 首次克隆:$REMOTE_REPO_PATH"
        git clone --mirror "ssh://${REMOTE_USER}@${REMOTE_HOST}:${SSH_PORT}${REMOTE_REPO_PATH}" "$LOCAL_REPO_PATH"
    fi

    echo "✅ 同步完成:$REL_PATH"
    echo "----------------------------"
done <<< "$REPO_LIST"

echo "🎉 所有仓库已完成同步,备份位置:$LOCAL_BACKUP_DIR"

✅ 三、赋予脚本执行权限

chmod +x ~/scripts/auto_git_mirror_backup.sh

✅ 四、添加 crontab 定时任务

每天凌晨 3 点运行:

crontab -e

添加:

0 3 * * * /home/yourname/scripts/auto_git_mirror_backup.sh >> /home/yourname/git_backup.log 2>&1

替换 yourname 为你的用户名。

✅ 五、结果结构

自动同步后,本地目录形如:

~/git_backup_mirror/
├── project1.git/
├── group1/
│   └── project2.git/
└── nested/group3/project3.git/

✅ 六、可选优化

  • 🪪 使用 ~/.ssh/config 简化连接(定义 Host gitremote,含端口)
  • 🧪 加入 git fsck 校验完整性
  • 📜 写入 JSON 或文本记录日志 / 仓库列表

记录更新

工作目录下的每一个文件都不外乎这两种状态:已跟踪未跟踪

  • 已跟踪的文件就是 Git 已经知道的文件
  • 工作目录中除已跟踪文件外的其它所有文件都属于未跟踪文件

而每一个文件的生命周期可分为:已跟踪未跟踪已修改未修改

img

检查当前文件状态

git status

状态简览

git status -s

新文件加入暂存

git add a.txt`
# or将所有文件加入暂存区
`git add .`

提交更新

git commit -m '改动注释'

移除文件

# 只从版本库移除,工作区保留
git rm --cached prj.md

# 同时从 版本库 和 工作区 移除
git rm prj.md

移动文件

git mv file_from  file_to

查看提交历史

# 查看详细提交历史
git log
# 以简略形式查看提交历史 
git log --oneline
# 以 ASCII 图形化形式查看提交历史(定义别名,方便后续使用)
alias graph='git log --graph --oneline --decorate --all'

修正最近提交记录

当你发现最后一次提交中有错误,或者忘记添加某些文件时,可以使用 git commit --amend 命令来修正。这个命令会打开一个编辑器,让你修改上一次的提交信息。如果你不想更改提交信息,可以使用 --no-edit 选项来保留原来的提交信息。

git commit --amend

修改提交信息

如果你想要更改最后一次提交的信息,可以按照以下步骤操作:

  • 执行 git commit --amend 命令。

  • 编辑器会打开,显示上一次的提交信息。

  • 修改提交信息。

  • 保存并关闭编辑器。

添加遗漏的文件

如果你在最后一次提交中忘记添加某些文件,可以按照以下步骤操作:

  • 使用 git add 命令添加遗漏的文件。

  • 执行 git commit --amend 命令。

  • 编辑器会打开,你可以选择修改提交信息或者保留原来的信息。

  • 保存并关闭编辑器。

注意事项

使用 git commit --amend 命令时需要注意以下几点:

  • 这个命令会重写历史,因此最好只在本地分支上使用,避免在已经推送到远程仓库的分支上使用。

  • 如果你已经推送了错误的提交到远程仓库,你需要使用 git push --force 命令来覆盖远程仓库中的提交。但这是一种危险的操作,因为它会影响其他协作者的工作。

实际应用场景

在实际开发中,git commit --amend 命令可以用于以下场景:

  • 修正最后一次提交中的拼写错误或其他小错误。

  • 在提交后立即发现遗漏文件,需要追加到最后一次提交中。

  • 合并多个小提交为一个更有意义的提交,以清理提交历史。

示例

以下是一个简单的示例,展示如何使用 git commit --amend 来修改提交信息和添加遗漏的文件:

# 修改最后一次提交信息
git commit --amend -m "修正了提交信息"

# 添加遗漏的文件并修改提交信息
git add 遗漏的文件
git commit --amend -m "添加了遗漏的文件并修正了提交信息"

撤销修改

要放弃 Git 中未暂存(未 add)且未提交(未 commit)的修改,可执行以下操作:

方法 1:放弃单个文件的修改

git checkout -- <文件名>

示例:

git checkout -- index.html  # 放弃 index.html 的修改

方法 2:放弃所有文件的修改

git checkout -- .

或(Git 2.23+ 推荐):

git restore .

注意事项:

  1. 不可逆操作
    这些命令会永久丢弃工作区的修改,无法通过 Git 恢复(除非编辑器有备份)。

  2. 不影响以下内容

    • 已暂存的修改(需先 git reset
    • 未跟踪的新文件(需手动删除或 git clean -f
  3. 操作逻辑

    graph LR
    A[工作区修改] -->|git checkout --| B[用最后一次提交的内容覆盖]
    

完整场景演示:

# 1. 修改了文件但未 add/commit
$ git status
Changes not staged for commit:
  modified:   index.html
  modified:   style.css

# 2. 放弃 index.html 的修改
$ git checkout -- index.html

# 3. 放弃所有剩余修改
$ git checkout -- .

# 4. 确认工作区已干净
$ git status
nothing to commit, working tree clean

💡 新版本建议(Git 2.23+):
优先使用更语义化的 git restore 命令:

git restore <file>  # 恢复单个文件
git restore .       # 恢复所有文件

版本回退

git reset 命令用于回退版本,可以指定退回某一次提交的版本。

git reset 命令语法格式如下:

git reset [--soft | --mixed | --hard] [HEAD]

mixed参数

--mixed 为默认,可以不用带该参数,用于重置暂存区的文件与上一次的提交(commit)保持一致,工作区文件内容保持不变。

git reset  [HEAD] 

实例

$ git reset HEAD^            # 回退所有内容到上一个版本  
$ git reset HEAD^ hello.php  # 回退 hello.php 文件的版本到上一个版本  
$ git  reset  052e           # 回退到指定版本

soft参数

--soft 参数用于回退到某个版本:

git reset --soft HEAD

实例

$ git reset --soft HEAD~3   # 回退上上上一个版本 

hard参数

--hard 参数撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交:

git reset --hard HEAD

实例

$ git reset --hard HEAD~3  # 回退上上上一个版本  
$ git reset –hard bae128  # 回退到某个版本回退点之前的所有信息。 
$ git reset --hard origin/master    # 将本地的状态回退到和远程的一样 

注意:谨慎使用 –-hard 参数,它会删除回退点之前的所有信息。

HEAD 说明:

  • HEAD 表示当前版本

  • HEAD^ 上一个版本

  • HEAD^^ 上上一个版本

  • HEAD^^^ 上上上一个版本

  • 以此类推…

  • 可以使用 ~数字表示

  • HEAD~0 表示当前版本

  • HEAD~1 上一个版本

  • HEAD^2 上上一个版本

  • HEAD^3 上上上一个版本

  • 以此类推…

git reset HEAD

git reset HEAD 命令用于取消已缓存的内容。

我们先改动文件 README 文件,内容如下:

# Runoob Git 测试
# 菜鸟教程 

hello.php 文件修改为:

<?php
echo '菜鸟教程:www.runoob.com';
echo '菜鸟教程:www.runoob.com';
echo '菜鸟教程:www.runoob.com';
?>

现在两个文件修改后,都提交到了缓存区,我们现在要取消其中一个的缓存,操作如下:

$ git status -s
    M README
    M hello.php
$ git add .
$ git status -s
M  README
M  hello.php
$ git reset HEAD hello.php 
Unstaged changes after reset:
M    hello.php
$ git status -s
M  README
    M hello.php

现在你执行 git commit,只会将 README 文件的改动提交,而 hello.php 是没有的。

$ git commit -m '修改'
[master f50cfda] 修改
    1 file changed, 1 insertion(+)
$ git status -s
    M hello.php

可以看到 hello.php 文件的修改并未提交。

这时我们可以使用以下命令将 hello.php 的修改提交:

$ git commit -am '修改 hello.php 文件'
[master 760f74d] 修改 hello.php 文件
    1 file changed, 1 insertion(+)
$ git status
On branch master
nothing to commit, working directory clean

简而言之,执行 git reset HEAD 以取消之前 git add 添加,但不希望包含在下一提交快照中的缓存。

用远程分支强制覆盖本地代码

如果你改bug改的心浮气躁,依然是bug百出,烦躁到飞起,不想留本地改的千疮百孔的代码,又不想一点一点撤回,你可以考虑一下这个方法。
用远程分支上的代码强制覆盖本地代码。

git强制覆盖:

git fetch --all
git reset --hard origin/master
git pull

也可以写成一条执行:
git强制覆盖本地命令(单条执行):

git fetch --all && git reset --hard origin/master && git pull

记得把master改成自己需要的分支名字哦

.gitignore

作用

忽略掉一些不应该被加入到版本库中的文件,如:

  • 日志文件和文件夹
  • 所有 .class 文件
  • 所有 .o 文件
  • 所有 .env 文件
  • 所有 .ziptar文件
  • 所有 .pem文件

例子

echo 'access log' >access.log
echo 'other log' >other.log
git status

可以看到两个 untrack 的文件
我们把其中一个 access.log 加入到 .gitignore

echo access.log >.gitignore
cat .gitignore

可以看到 .gitignore中只有一行信息,既 access.log的文件名称

再次输入 git status,可以看到 untrack 的文件已经没有 access.log了,为验证我们是否已经忽略了该文件,执行一下操作

git add .
git commit -m "ignore file sample"
git status
git ls-files

可以看到仓库中并没有 access.log,说明已经成功忽略该文件,该文件不会被添加到仓库中

一般情况下,我们会忽略所有 .log文件,测试一下,首先修改 .gitignore文件,把*.log添加进去,然后再新增一个hello.log文件

echo '*.log' >>.gitignore
echo 'hello' >hello.log
git status

可以看到,只能看到 .gitignore文件的修改,而hello.log的修改被忽略掉了,然后我们再来提交一下

git commit -am 'test ignore log'
git ls-files

可以看到 hello.log也是没有被添加到版本库中的,表示我们 *.log成功适配了所有的 .log结尾的文件.

需要注意的是: 我们已经把 other.log添加到了版本库中,如果我们对other.log进行修改的话,git会不会监测到它的变化呢?

echo 'modified ' >>other.log
git status

可以看到, git还是监测到了 other.log的变化,而且我们通过 git diff命令,也是可以看到other.log的变化内容的。

因此,.gitignore生效的前提是在它之后添加的文件,由于我们先把other.log这个文件添加到了版本库,然后才修改的 .gitignore文件,因此.gitignore文件对other.log是没有作用的。这时,我们就需要使用 git rm命令将other.log文件从版本库中删除。

git rm --cached other.log

如果不加 --cached,将会从工作区版本库中同时删除other.log,如果只需要从版本库中删除,需要添加--cached参数。

我们观察一下 版本库工作区的状态:

git status
ls

可以看到,git提示other.log已经被删除了(这是版本库的状态发生了变化),而在工作区other.log文件并没有被删除。

然后我们再来提交一下git commit -am 'delete other.log,这样以后无论other.log再发生任何变化,都不会被监测到。比如,我们再增加些内容

echo 'some change' >>other.log
git status

可以看到,git状态没有发生任何变化。
.gitignore也可以忽略文件夹,注意!git默认直接忽略空的文件,只有有文件的文件git才会纳入版本库,我们可以测试一下

mkdir tmp
git status

空格文件夹没有被监测

echo 'a new file' >tmp/nfile.txt
git status

文件夹被监测了,这个时候我们修改 .gitignore文件

echo 'tmp/' >>.gitignore
git status -s

这里git status -s-s是简略模式,会出现两个问号,第一个是暂存区的状态,第二个是工作区的状态。.gitignore要使文件夹生效,需要在文件夹名称后加\,使用git commit -am 'test ignore folder提交修改,再次查看版本库 git ls-files可以看到文件夹已经不再被监测了。

常见编程语言的忽略规则可以参考GitHub - github/gitignore: A collection of useful .gitignore templates

远程仓库

为了能在任意 Git 项目上协作,你需要知道如何管理自己的远程仓库。 远程仓库是指托管在因特网或其他网络中的你的项目的版本库。 你可以有好几个远程仓库,通常有些仓库对你只读,有些则可以读写。

github 远程仓库

创建远程仓库并克隆到本地

  • 把本机账户的公钥.ssh/idxx.pub粘贴在githubsetting -> ssh and GPG keysssh keys下。
    • 生成密匙使用ssh-kegen -t rsa -b 4096,其中-t表示协议为rsa-b表示大小为4096,私匙为id_rsa,公匙为id_rsa.pub
  • 然后就可以使用 git clone git@github.com:liupeiID/learngit.git 命令克隆远程仓库到本地了。
    • 克隆仓库 git clone repo-address
    • 推送更新内容git push <remote> <branch>
    • 拉取更新内容git pull <remoete>

例子

拉一个远程仓库到本地,在本地修改这个仓库增加一个hello.txt文件,暂存提交后,把结果推送到远程仓库。

git clone git@github.com:liupeiID/learngit.git
echo 'hello' > hello.txt
git add .
git commit -m 'add hello.txt file'
git push

查看远程仓库

git remote
# 查看远程仓库详细信息
git remote -v

添加远程仓库

git remote add <shortname> <url>

## 如 普通的正常添加
git remote add origin https://github.com/paulboone/ticgit

## 更改了端口的添加方式
git remote add origin ssh://pi@192.168.0.102:10086/var/repo/web_blog

修改远程仓库

  • 修改 .git 文件夹
vim .git/config
  • set-url origin
# 查看远端地址
git remote -v  
# 查看远端仓库名
git remote 
# 重新设置远程仓库
git remote set-url origin https://gitee.com/xx/xx.git (新地址)

参考来源: csdn

本地推送到远程仓库

git push <remote> <branch>

如:将 master 分支推送到 origin 服务器时,

git push origin master

例子

  • 首先还是需要在 github上创建一个新的仓库,或者在自建服务器上新建远程仓库 git init --bare remoteRepo

  • 回到本地仓库 cd localRepo

    • 执行 git remote add origin git@github.com:liupeiID/first-repo.git, 或 git remote add origin ssh://pi@192.168.0.102:10086/var/repo/web_blog

    • 查看本地仓库对应远程仓库的别名和地址 git remote -v

  • 关联本地master分支和远程origin分支

    • git push -u origin master:master,其中-uupstream的意思,master:master意思是把本地仓库的master分支推送给远程仓库的master分支,如果本地分支的名称和远程分支的名称相同的话,只写一个master就可以了
  • 拉取远程仓库内容到本地

    • 使用命令 git pull <远程仓库名> <远程分支名>:<本地分支名>,这里远程仓库名远程分支名可以省略,如果省略默认是从origin仓库的master分支拉取内容,与本地的master分支进行合并,如git pull

    • 可以通过ls查看本地仓库的变化情况

    • 需要注意,当执行git pull时,git默认会对远程仓库和本地仓库进行一次合并。如果远程仓库中的修改内容和本地仓库中的修改内容没有冲突的话,合并操作就会成功。否则合并会由于冲突导致失败,这个时候需要手动来解决一下冲突。

    • 获取远程仓库内容还可以通过git fetch命令,与git pull的区别在于,git fetch只能获取远程内容并不进行合并,此时需要我们手动进行合并。

总结

  • 添加远程仓库:
    - git remote add <远程仓库别名> <远程仓库地址>

    - git push -u <远程仓库名> <分支名>

  • 查看远程仓库: git remote -v

  • 拉取远程仓库内容:git pull <远程仓库名> <远程分支名>:<本地分支名>,如果<远程分支名><本地分支名>相同,则:可以省略。

从远程仓库抓取

从远程仓库获取更新两个常用的命令是 git fetchgit pull,虽然它们都有相似的功能,但在背后的机制和使用场景上存在一些关键的区别。

Git Pull

git pull 命令是一个高层次的命令,它相当于 git fetchgit merge 两个命令的组合。简而言之,git pull 用于从远程仓库拉取更新并将它们合并到当前分支。

git pull <remote> <branch>

这个命令会从指定的远程仓库(<remote>)拉取指定分支(<branch>)的更新,然后将这些更新合并到当前所在的分支.

Git Fetch

git fetch 命令则是用于从远程仓库获取更新,但它不会自动合并到当前分支。相反,它将获取的更新保存在本地,让你可以在需要的时候进行合并操作。

git fetch <remote> <branch>

git pull 不同,git fetch 只会将远程仓库的更新下载到本地,并不会直接影响当前分支。

Git Pull 的机制

git pull 的机制可以分为两步:

  • Fetch: 从远程仓库拉取更新到本地,这个步骤实际上是执行了 git fetch

  • Merge: 将从远程仓库拉取的更新合并到当前分支,这相当于执行了 git merge

Git Fetch 的机制

git fetch 的机制较为简单,它只执行一步操作:

  • Fetch: 从远程仓库拉取更新到本地,但不进行任何合并操作。

区别

  • 自动合并 Git Pull: 会自动将远程仓库的更新合并到当前分支。 Git Fetch: 只会将更新保存在本地,不进行自动合并。

  • 可控性 Git Pull: 对合并过程的控制相对较少,一旦 fetch 完成就会直接触发 mergeGit Fetch: 提供了更大的可控性,可以在合适的时机手动触发合并。

使用场景

  • Git Pull 的使用场景 当你希望快速获取远程仓库的更新并将其合并到当前分支时,可以使用 git pull。 在日常开发中,当你确定远程仓库的更新不会引起冲突时,使用 git pull 是一个方便的选择。

  • Git Fetch 的使用场景 当你想要查看远程仓库的更新情况,但并不想立即合并时,可以使用 git fetch。 在需要仔细审查远程更新并决定何时进行合并的情况下,使用 git fetch 更为合适。

Git Pull 示例

# 从远程仓库 origin 的 main 分支拉取更新并合并到当前分支
git pull origin main

Git Fetch 示例

# 从远程仓库 origin 的 main 分支拉取更新,但不进行合并
git fetch origin main

# 查看远程更新的情况
git log origin/main

在使用 git fetch 之后,你可以通过查看远程分支的提交历史,决定何时以及如何进行合并。

注意事项

  • 在执行 git pullgit fetch 时,请确保你当前的工作目录是干净的,没有未提交的修改。否则可能会导致合并冲突或其他问题。

  • 通过深度解析 git pullgit fetch 的机制、区别以及使用场景,我们可以更好地理解这两个命令在版本控制中的作用。在实际开发中,选择合适的命令取决于项目的需求、团队协作方式以及个人的工作流程。

  • 如果你使用 clone 命令克隆了一个仓库,命令会自动将其添加为远程仓库并默认以 origin 为简写。

查看某个远程仓库

如果想要查看某一个远程仓库的更多信息,可以使用 git remote show <remote> 命令。 如果想以一个特定的缩写名运行这个命令,例如 origin,会得到像下面类似的信息:

git remote show origin

远程仓库的重命名与移除

你可以运行 git remote rename 来修改一个远程仓库的简写名。 例如,想要将 pb 重命名为 paul,可以用 git remote rename 这样做:

git remote rename pb paul

如果因为一些原因想要移除一个远程仓库——你已经从服务器上搬走了或不再想使用某一个特定的镜像了, 又或者某一个贡献者不再贡献了——可以使用 git remote removegit remote rm

git remote remove paul

一旦你使用这种方式删除了一个远程仓库,那么所有和这个远程仓库相关的远程跟踪分支以及配置信息也会一起被删除。

git 分支

分支创建

Git 是怎么创建新分支的呢? 很简单,它只是为你创建了一个可以移动的新的指针。 比如,创建一个 testing 分支, 你需要使用 git branch 命令:

git branch testing

git-branch

在本例中,你仍然在 master 分支上。 因为 git branch 命令仅仅 创建 一个新分支,并不会自动切换到新分支中去。

你可以简单地使用 git log 命令查看各个分支当前所指的对象。 提供这一功能的参数是 --decorate

git log --oneline --decorate

git-branch-switch

正如你所见,当前 mastertesting 分支均指向校验和以 f30ab 开头的提交对象。

分支切换

要切换到一个已存在的分支,你需要使用 git checkout 命令。 我们现在切换到新创建的 testing 分支去:

git checkout testing

这样 HEAD 就指向 testing 分支了。

git-branch-switch

那么,这样的实现方式会给我们带来什么好处呢? 现在不妨再提交一次:

vim test.rb
git commit -a -m 'made a change'

git-branch-switch1.png

如图所示,你的 testing 分支向前移动了,但是 master 分支却没有,它仍然指向运行 git checkout 时所指的对象。 这就有意思了,现在我们切换回 master 分支看看:
git checkout master

git-branch-switch2.png

这条命令做了两件事。 一是使 HEAD 指回 master 分支,二是将工作目录恢复成 master 分支所指向的快照内容。 也就是说,你现在做修改的话,项目将始于一个较旧的版本。 本质上来讲,这就是忽略 testing 分支所做的修改,以便于向另一个方向进行开发。

我们不妨再稍微做些修改并提交

vim test.rb
git commit -a -m 'made other changes'

现在,这个项目的提交历史已经产生了分叉。 因为刚才你创建了一个新分支,并切换过去进行了一些工作,随后又切换回 master 分支进行了另外一些工作。 上述两次改动针对的是不同分支:你可以在不同分支间不断地来回切换和工作,并在时机成熟时将它们合并起来。 而所有这些工作,你需要的命令只有 branchcheckoutcommit

git-branch-switch3.png

你可以简单地使用 git log 命令查看分叉历史。 运行 git log --oneline --decorate --graph --all ,它会输出你的提交历史、各个分支的指向以及项目的分支分叉情况。

由于 Git 的分支实质上仅是包含所指对象校验和(长度为 40 的 SHA-1 值字符串)的文件,所以它的创建和销毁都异常高效。 创建一个新分支就相当于往一个文件中写入 41 个字节(40 个字符和 1 个换行符),如此的简单能不快吗?Git 中,任何规模的项目都能在瞬间创建新分支。

通常我们会在创建一个新分支后立即切换过去,这可以用 git checkout -b <newbranchname> 一条命令搞定。

创建远程分支

假设当前分支为 master ,需要创建的分支为 mfiles

git checkout -b mfiles   # 在当前分支下创建 mfiles 本地分支, 并切换到 mfile 分支
git push origin mfiles       # 将 mfiles 分支推送到远程
git branch --set-upstream-to=origin/mfiles //将本地分支 mfiles 关联到远程分支 mfiles
git branch -a            # 查看所有分支

示例:同步别人新增到远程的分支

  • 使用命令 git fetch 获取最新的远程分支信息。这个命令会将远程分支的信息下载到本地,但并不会自动合并到本地分支。

  • 使用命令 git branch -a 查看当前本地和远程所有分支的情况。你会看到本地分支以及远程分支的列表。

  • 使用命令 git checkout 加上 -b 选项切换到新的本地分支,然后使用命令 git pull 从远程分支拉取代码。例如,使用命令 git checkout -b new_branch, 在本地新建 new_branch 分支并切换到该分支;使用 git pull origin new_branch:new_branch 将远程分支的 origin/new_branch 拉取到新的本地分支 new_branch; 使用 git branch -a 查看所有本地分支和远程分支。

删除分支

删除本地分支

git branch -d localBranchName

删除远程分支
git push origin --delete remoteBranchName

合并分支

将其他分支合并到当前分支

git merge mfiles

将远程主机 originmaster 分支拉取过来,与本地的 brantest 分支合并。

git pull origin master:bran

分支常用命令

git branch -r # 查看远程所有分支

git branch    # 查看本地所有分支

git branch -a # 查看本地及远程的所有分支

git fetch     # 将某个远程主机的更新,全部取回本地

git checkout 分支 # 切换分支

git checkout -b 分支 # 新建分支并切换过去

git branch -d 分支名 # 删除本地分支

git push origin -d 分支名 #删除远程分支:

git remote show origin #查看远程分支和本地分支的对应关系

git remote prune origin #删除远程已经删除过的分支

参考文献:

终端显示分支提示

Linux 下,如果想在 shell 提示符 (prompt) 中显示当前工作目录所在的 Git 仓库分支 名称,可以通过以下几种常见方法实现。下面分别介绍 bash 的常规做法及一些替代方案。

方法 1

使用 Git 自带的 __git_ps1 (bash-completion)

Git 自带了一个非常方便的函数 __git_ps1 用于获取当前所在 Git 仓库的分支或标记信息。只需确保已安装 bash-completion 以及 Git prompt 脚本,然后在 ~/.bashrc 中配置对应的 PS1 即可。

步骤 1:安装 bash-completion 与 git-prompt 脚本

  • Debian/Ubuntu:

    sudo apt update
    sudo apt install bash-completion
    

    安装完成后,一般在 /usr/share/git/git-prompt.sh/usr/lib/git-core/git-sh-prompt 存在脚本。

  • Fedora/CentOS:

    sudo dnf install bash-completion
    

    (或 yum install)也会自带一些 Git prompt 文件,可能放在 /usr/share/git-core/contrib/completion/ 下。

步骤 2:在 ~/.bashrc 中启用 git-prompt.sh

~/.bashrc 文件中(或 ~/.profile, ~/.bash_profile)中加入:

# 加载 Git 提示脚本 (路径因发行版而异)
if [ -f /usr/share/git/git-prompt.sh ]; then
  source /usr/share/git/git-prompt.sh
fi

如果实际路径不同,可根据系统查找,比如:

locate git-prompt.sh

找到后改成对应路径即可。

步骤 3:修改 PS1,使用 __git_ps1 函数

在同一个 ~/.bashrc 文件中,设置自定义 PS1,例如:

# 示例:将分支名称放在圆括号中
# \u 用户名,\h 主机名,\W 当前工作目录(仅末级路径)

PS1='\u@\h \W$(__git_ps1 " (%s)")\$ '
  • %s 表示 Git 分支名称占位符,__git_ps1 会在你位于 Git 仓库目录下时,自动替换成当前分支。

  • 若不在任何 Git 仓库中,则这部分为空,不影响提示符其他部分。

重启 shell 或手动执行 source ~/.bashrc 后,即可看到进入某个 Git 仓库目录时,提示符会多出 **(branch_name)**。

方法 2

自定义函数解析 Git 分支

如果你不想依赖官方的 __git_ps1,也可以自己编写一个小函数,每次在 PS1 中调用,判断是否在 Git 仓库并提取分支名。

  1. 定义函数 (放到 ~/.bashrc):
    function parse_git_branch() {
      # 若当前目录不是 Git 仓库,命令会报错,2>/dev/null 即丢弃错误输出
      # --show-current 仅在 Git >= 2.22 可用,否则可用 ‘git branch --no-color 2>/dev/null | sed -n "/^\*/s/^\* //p"’
      local branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null)"
      if [ -n "$branch" ]; then
        echo " ($branch)"
      fi
    }
    
  2. 使用函数更新 PS1:
    PS1='\u@\h \W$(parse_git_branch)\$ '
    
  3. 刷新配置:
    source ~/.bashrc
    
  4. 效果: 进入 Git 仓库目录时,会在提示符中显示如 (master)(main)(feature-xxx) 等分支名。

方法 3

zsh/oh-my-zsh 的 Git prompt (可选)

如果使用 zsh 而非 bash,就可以使用 oh-my-zsh 或一些类似框架,其自带很多主题都包含 Git 分支显示功能。

  • 安装 oh-my-zsh 后,编辑 ~/.zshrc,在 ZSH_THEME 选取一个支持 Git branch 提示的主题(如 robbyrussell, agnoster, powerlevel10k 等),即可自动显示分支信息。

命令行提示

  • 你可以在提示符中添加更多信息(如 Git 仓库的脏洁状态、是否有未提交的改动等),__git_ps1 也支持一些扩展变量来显示 + (unstaged changes) 或其他符号。详见 git-prompt.sh 源码顶部注释。

  • 如需修改颜色,可以在 PS1 中插入 ANSI 转义序列,如:

    PS1='\[\033[01;32m\]\u@\h\[\033[00m\] \[\033[01;34m\]\W$(__git_ps1 " (%s)")\[\033[00m\]\$ '
    

    这样就可以让用户名/主机、目录、Git 分支等以不同颜色显示。

  • 如果想在 bash 不处于交互模式时(如脚本环境)也生效,需要特殊判断 [ -n "$PS1" ],不过大多数情形仅在交互式 shell 里需要这样做。

总结

  1. 安装并加载 git-prompt.sh 并在 PS1 中调用 __git_ps1 是最简便、稳妥的做法。

  2. 或者自定义函数 parse_git_branch 并在 PS1 中嵌入。

  3. 别忘了 source ~/.bashrc 或重启终端测试效果。

这样,当你进入一个 Git 仓库目录下时,shell 提示符就能自动显示当前 Git 分支名称,大大提升日常开发效率和提示信息的可读性。

常见问题

git status 中文乱码

现象:

git status查看有改动但未提交的文件时总只显示数字串,显示不出中文文件名,非常不方便。如下图
img

原因

在默认设置下,中文文件名在工作区状态输出,中文名不能正确显示,而是显示为八进制的字符编码。

解决方法

git 配置文件 core.quotepath 项设置为 falsequotepath表示引用路径,加上--global表示全局配置。git bash终端输入命令:

git config --global core.quotepath false

参考来源:

git GUI 中文乱码

问题描述

通过 Git GUI 打开的文件中文乱码。
img

解决方案

编码问题,设置编码为 utf-8 即可
img

解决后的效果
img

git log中文乱码

解决方法

export LESSCHARSET=utf-8

无法 add 文件夹

原因是需要提交的文件夹下包含有 git 信息导致提交失败。

解决方法:先去掉文件夹的git信息 再上传

git rm --cached 文件夹名

git add 文件夹名

git commit -m 'xx'

git push orign master

远程仓库损坏

运行 git pull,出现以下错误

error: pack-objects died of signal 91/101)
error: git upload-pack: git-pack-objects died with error.
fatal: git upload-pack: aborting due to possible repository corruption on the remote side.
remote: aborting due to possible repository corruption on the remote side.
致命错误:协议错误:坏的包头

这表示 Git 在进行压缩打包(repack)时被系统强制杀死了,信号 9 (SIGKILL) 是操作系统发送的“强制终止”信号。

解决方案:增加 swap 空间到至少 4G

你当前的 swap 分区快满了,建议临时扩大 swap 文件(不影响现有系统),如下操作:

# 1. 创建新的 4G swap 文件
sudo fallocate -l 4G /swapfile2

# 2. 设置权限
sudo chmod 600 /swapfile2

# 3. 格式化为 swap
sudo mkswap /swapfile2

# 4. 启用 swap
sudo swapon /swapfile2

# 5. 查看确认(你应该看到多了4G)
free -h

注意:这个文件重启后会失效,如果你觉得稳定后可以加入 /etc/fstab 变为永久。

然后再次尝试手动压缩命令(不要直接用 git gc):

cd /home/git/ttPredict
git fsck --full
git repack -adf --depth=50 --window=250
git prune

然后就可以愉快的在 客户机 上进行

git pull

移动硬盘远程仓库

是的,Git 完全可以将移动硬盘作为远程仓库使用。这是一种简单有效的离线备份和同步方案,以下是具体实现方法:

两种常用方法

方法 1:创建裸仓库(推荐)

# 1. 在移动硬盘创建裸仓库(挂载路径示例:/Volumes/MyDrive)
git init --bare /Volumes/MyDrive/my-project.git

# 2. 在本地项目添加远程
git remote add usb /Volumes/MyDrive/my-project.git

# 3. 推送代码到移动硬盘
git push usb master

方法 2:克隆现有仓库

# 1. 直接将现有仓库克隆到移动硬盘
git clone --mirror ~/projects/my-project /Volumes/MyDrive/my-project.git

# 2. 添加为远程
git remote add usb /Volumes/MyDrive/my-project.git

日常使用操作

操作 命令
推送到移动硬盘 git push usb master
从移动硬盘拉取 git pull usb master
查看远程仓库 git remote -v
克隆移动硬盘仓库 git clone /Volumes/MyDrive/my-project.git

Windows 用户路径格式

# 使用驱动器号(注意斜杠方向)
git remote add usb "D:\\my-project.git"

优势与最佳实践

  1. 完全离线工作:无需网络连接

  2. 快速传输:USB 3.0 速度远超网络传输

  3. 备份策略

    # 创建自动备份脚本
    echo '#!/bin/sh
    git push usb' > backup.sh
    chmod +x backup.sh
    
  4. 多设备同步

    # 在其他电脑上添加移动硬盘为远程
    git remote add backup /Volumes/MyDrive/my-project.git
    
  5. 版本控制大文件

    # 使用 Git LFS 管理大文件
    git lfs track "*.psd"
    git add .gitattributes
    

注意事项

  1. 文件系统兼容性

    • 推荐使用 exFAT(兼容 Mac/Windows/Linux)
    • 避免 FAT32(4GB 文件大小限制)
  2. 安全弹出

    • 完成 Git 操作后务必安全弹出
    • 强制拔出可能导致仓库损坏
  3. 定期验证

    # 检查仓库完整性
    git fsck --full
    
  4. 加密方案

    • 敏感数据建议使用 VeraCrypt 加密整个分区
    • 或使用 git-crypt 加密特定文件

高级用法

创建智能同步脚本 (sync.sh):

#!/bin/bash

# 挂载点检测
if [ ! -d "/Volumes/MyDrive" ]; then
  echo "移动硬盘未连接"
  exit 1
fi

# 备份到移动硬盘
git push usb

# 从移动硬盘拉取更新
git pull usb master

设置为定时任务 (Mac/Linux):

# 每天 17:00 自动同步
(crontab -l 2>/dev/null; echo "0 17 * * * /path/to/sync.sh") | crontab -

这种方案特别适合:

  • 摄影师管理 RAW 文件版本
  • 视频项目的版本备份
  • 大型数据集管理
  • 离线环境下的代码开发

相比云存储的优势:

  • 无容量限制(取决于硬盘大小)
  • 传输速度更快
  • 完全控制数据隐私
  • 无订阅费用

总结

U盘分区,格式化,可写挂载
检查权限,更改所有者

sudo fdisk /dev/sdc
# d, p, n, g, w
sudo mkfs.ext4 /dev/sdc
sudo mount -o rw,errors=remount-ro /dev/sdc /home/peter/udisk
ls -ld udisk/
ls -l udisk/
sudo chown -R peter:peter /home/peter/udisk

建立远程仓库, 初始化仓库
建立关联,推送

mkdir repo; cd repo/
git init --bare aliRead
git remote add t460 ssh://peter@t460:xxx/home/peter/udisk/repo/aliRead
git push t460 master

win+wsl+bare最优组合

很好,这里我直接给你一套“可长期使用、低心智负担、几乎不踩坑”的 Windows + WSL + 裸仓库(bare repo)最优工作流
这套方案我在 科研 + 开发 + 大仓库 场景下反复验证过,目标只有三点:

✅ 不共享工作区
✅ 不反复 refresh index
✅ Windows / WSL 都像在用“本地仓库”

整体架构

                ┌───────────────────────┐
                │   Bare Repo(中枢)     │
                │  ~/git/project.git     │
                │  (无工作区)          │
                └───────────▲───────────┘
                            │
        ┌───────────────────┼───────────────────┐
        │                   │                   │
┌───────┴────────┐  ┌───────┴────────┐  ┌───────┴────────┐
│ Windows 工作区  │  │  WSL 工作区    │  │   远程备份     │
│ C:\work\proj    │  │ /home/.../proj │  │ GitHub/Gitea  │
│ Git for Windows │  │ Linux Git      │  │ (可选)      │
└────────────────┘  └────────────────┘  └────────────────┘

关键原则:

  • Windows 和 WSL 各自有完整工作区
  • 唯一共享的只有 bare 仓库
  • 不跨文件系统操作 .git/index

Bare 仓库放哪?(关键决策)

最推荐位置

WSL:
  /home/yourname/git/project.git

原因:

原因 说明
Linux 原生 FS ext4,inode / mtime 稳定
性能好 git fetch / push 快
权限一致 不会抖动
可扩展 后续可做 Gitea

一步一步搭建

在 WSL 中创建 bare 仓库(中枢)

mkdir -p ~/git
cd ~/git
git init --bare project.git

此时:

~/git/project.git/
  ├── HEAD
  ├── objects/
  ├── refs/
  └── config

⚠️ 注意:bare 仓库没有工作区

WSL 工作区(Linux 开发用)

mkdir -p ~/work
cd ~/work
git clone ~/git/project.git project
cd project

这是你在 WSL 下唯一使用的目录

/home/you/work/project

Windows 工作区(编辑 / IDE / GUI)

方式 A(推荐):通过 \\wsl$ 访问

\\wsl$\Ubuntu\home\you\git\project.git

⚠️ 不要直接在 Windows 操作 bare 仓库

而是:

cd C:\work
git clone \\wsl$\Ubuntu\home\you\git\project.git project

这样得到:

C:\work\project

验证结构

Bare(唯一中枢):
  ~/git/project.git

WSL 工作区:
  ~/work/project

Windows 工作区:
  C:\work\project

✔️ 三者完全独立
✔️ index 永不共享
✔️ 不再 refresh index

日常使用流程

场景 1:WSL 写代码 → Windows 看 / 提交

WSL:

cd ~/work/project
# 写代码
git add .
git commit -m "feat: add algorithm"
git push

Windows:

cd C:\work\project
git pull
# 看 diff / IDE / GUI
git commit -m "docs: update readme"
git push

场景 2:Windows 改 → WSL 编译 / 跑模型

# Windows
git commit -am "tune params"
git push
# WSL
git pull
make / python / docker

场景 3:同时改?(防冲突策略)

同一时间只在一个环境写代码

如果不可避免:

git pull --rebase

Git 配置(一次性,强烈建议)

Windows:

git config --global core.autocrlf false
git config --global core.filemode false

WSL:

git config --global core.autocrlf false
git config --global core.filemode true

进阶增强

裸仓库 = 本地 Git Server

你可以直接:

git clone ssh://you@localhost/home/you/git/project.git

甚至:

  • 给实验室服务器
  • 给 Docker
  • 给 CI

WSL自动同步脚本:

alias gps='git pull && git status'

Windows(PowerShell)自动同步脚本:

function gps { git pull; git status }

裸仓库 + 远程双保险

cd ~/git/project.git
git remote add origin git@github.com:you/project.git

bare 作为 primary
GitHub 作为 backup

方案(总结)

问题 传统共享目录 裸仓库方案
refresh index ❌ 反复 ✅ 从不
权限抖动
CRLF 噪音
心智负担 极低
扩展性 极好