Git "rebase" 但忽略新 .gitignore 中的文件
Git "rebase" but ignoring files in new .gitignore
有没有一种方法可以将源分支的提交重播到目标分支,但考虑到目标分支中 .gitignore
中所做的更改?
场景如下:
假设我从 master 分支出来并开始提交文件,包括 .bin
应该在 .gitignore
中但没有的文件。有什么方法可以让我去掌握,将“*.bin”提交到 .gitignore
,然后在重新定基(或其他一些自动操作)时修复我的主题分支?通过修复我的意思是删除任何 .bin 文件的变更集,这些文件现在被忽略了。这意味着 1) 如果提交在 a.txt
和 foo.bin
上有变化,它应该只提交 a.txt
和 2) 如果提交只在 foo.bin
上有变化,它应该是完全下降
目标是轻松清除仅在合并请求时发现的多个错误。
常规 git rebase
无效。即使在 repo 的(新)线性历史记录中,错误提交的文件仍然提交,gitignore 模式在错误提交之前就存在
不,您需要使用 git rm
来删除您已经跟踪的文件(或者如果您想删除它的所有痕迹 git-filter-branch
)。这是 gitignore 手册页中的相关位(注意最后一句话):
A gitignore file specifies intentionally untracked files that Git
should ignore. Files already tracked by Git are not affected
Is there a way to replay commits from a source branch into a destination branch but taking into consideration changes made in .gitignore
in the destination branch?
是的,这是可能的,但是,这需要一些脚本编写工作。 (我在下面循环中的示例脚本甚至可以按原样为您工作。)基本上,您将模拟变基,但在每次提交之间有几个步骤。该算法看起来像这样:
- 获取要重写的提交列表并将它们存储在数组或列表中。
- 将您的源分支重置为目标。 (
.gitignore
文件现在应该就位。)
- 对于列表中的每个提交:使用
--no-commit
标志精心挑选提交,这样您就不会完成提交,然后 reset
取消暂存更改,然后 add
他们听从 .gitignore
的指示。
这是一个工作示例 bash 脚本(将其保存为文件并 运行 将其放在空目录中进行测试):
#!/bin/bash -v
git init
git branch -m main # rename to main in case that's not your default branch name
echo asdf > asdf.txt && git add . && git commit -m "Add asdf.txt"
git branch test-branch
echo "*.log" > .gitignore && git add . && git commit -m "Add .gitignore"
git switch test-branch
echo abc > abc.txt
echo def > def.log
git add . && git commit -m "Add abc.txt and def.log"
echo ghi > ghi.txt
echo hij > hij.log
git add . && git commit -m "Add ghi.txt and hij.log"
git log --all --graph --name-only
# Get all the commit IDs that would be rebased if we rebased test-branch onto main,
# and store them into an array in reverse order
declare -a commitIDs=(`git log main..test-branch --pretty=format:"%h" --reverse`)
# reset test-branch to main
git reset --hard main
# loop through the commitIDs and cherry-pick each one without committing
for i in "${commitIDs[@]}"
do
echo "About to cherry-pick commit $i"
git cherry-pick $i --no-commit # this leaves the commit staged
git reset # unstage so we can commit with the .gitignore
git add . # this doesn't add ignored files
git commit --reuse-message=$i
done
git log --all --graph --name-only
完成后,查看两个 git log
语句的输出。第一个有 2 个提交,每个提交都有一个 .txt 和 .log 文件。第二个使用 .gitignore
文件从这些提交中删除所有 .log 文件。
请注意,我在重写时使用了以前的提交消息,因为这通常是您想要的。但是我故意以这样的方式命名我的提交,以突出显示您不想这样做的场景,例如,当您忽略的文件名在提交消息中指定时。
有没有一种方法可以将源分支的提交重播到目标分支,但考虑到目标分支中 .gitignore
中所做的更改?
场景如下:
假设我从 master 分支出来并开始提交文件,包括 .bin
应该在 .gitignore
中但没有的文件。有什么方法可以让我去掌握,将“*.bin”提交到 .gitignore
,然后在重新定基(或其他一些自动操作)时修复我的主题分支?通过修复我的意思是删除任何 .bin 文件的变更集,这些文件现在被忽略了。这意味着 1) 如果提交在 a.txt
和 foo.bin
上有变化,它应该只提交 a.txt
和 2) 如果提交只在 foo.bin
上有变化,它应该是完全下降
目标是轻松清除仅在合并请求时发现的多个错误。
常规 git rebase
无效。即使在 repo 的(新)线性历史记录中,错误提交的文件仍然提交,gitignore 模式在错误提交之前就存在
不,您需要使用 git rm
来删除您已经跟踪的文件(或者如果您想删除它的所有痕迹 git-filter-branch
)。这是 gitignore 手册页中的相关位(注意最后一句话):
A gitignore file specifies intentionally untracked files that Git should ignore. Files already tracked by Git are not affected
Is there a way to replay commits from a source branch into a destination branch but taking into consideration changes made in
.gitignore
in the destination branch?
是的,这是可能的,但是,这需要一些脚本编写工作。 (我在下面循环中的示例脚本甚至可以按原样为您工作。)基本上,您将模拟变基,但在每次提交之间有几个步骤。该算法看起来像这样:
- 获取要重写的提交列表并将它们存储在数组或列表中。
- 将您的源分支重置为目标。 (
.gitignore
文件现在应该就位。) - 对于列表中的每个提交:使用
--no-commit
标志精心挑选提交,这样您就不会完成提交,然后reset
取消暂存更改,然后add
他们听从.gitignore
的指示。
这是一个工作示例 bash 脚本(将其保存为文件并 运行 将其放在空目录中进行测试):
#!/bin/bash -v
git init
git branch -m main # rename to main in case that's not your default branch name
echo asdf > asdf.txt && git add . && git commit -m "Add asdf.txt"
git branch test-branch
echo "*.log" > .gitignore && git add . && git commit -m "Add .gitignore"
git switch test-branch
echo abc > abc.txt
echo def > def.log
git add . && git commit -m "Add abc.txt and def.log"
echo ghi > ghi.txt
echo hij > hij.log
git add . && git commit -m "Add ghi.txt and hij.log"
git log --all --graph --name-only
# Get all the commit IDs that would be rebased if we rebased test-branch onto main,
# and store them into an array in reverse order
declare -a commitIDs=(`git log main..test-branch --pretty=format:"%h" --reverse`)
# reset test-branch to main
git reset --hard main
# loop through the commitIDs and cherry-pick each one without committing
for i in "${commitIDs[@]}"
do
echo "About to cherry-pick commit $i"
git cherry-pick $i --no-commit # this leaves the commit staged
git reset # unstage so we can commit with the .gitignore
git add . # this doesn't add ignored files
git commit --reuse-message=$i
done
git log --all --graph --name-only
完成后,查看两个 git log
语句的输出。第一个有 2 个提交,每个提交都有一个 .txt 和 .log 文件。第二个使用 .gitignore
文件从这些提交中删除所有 .log 文件。
请注意,我在重写时使用了以前的提交消息,因为这通常是您想要的。但是我故意以这样的方式命名我的提交,以突出显示您不想这样做的场景,例如,当您忽略的文件名在提交消息中指定时。