Git 分支 A 和 B 之间的差异,select 一组文件模式更改,将这些更改重置为分支 A

Git diff between branch A & B, select a set of file mode changes, reset those changes to branch A

我愿意

第 1 步)使分支 A 和 B 之间存在 Git 差异,

第 2 步)select 一组更改(select 那些更改,其中文件权限从模式 100755 更改为模式 100644),

步骤 3) 将那些 selected 更改重置为分支 A(或从分支 B 中挑选更改)。

如何使用 git?

部分解:

第 1 步和第 2 步)我能够列出那些具有

的文件

git diff --name-only "A" "B" | grep 'mode change 100755 => 100644'

步骤 3) 如何将那些 selected 文件模式更改重置为分支 A(或从分支 B 中挑选更改)? 我只想将步骤 1 中 selected 文件的文件状态恢复到它们在分支 A 中的状态。

注意:我有几千个文件,所以一个一个地挑选樱桃不是解决办法。

@jthill:不幸的是,在 MINGW64 (Windows) 上执行 chmod 时没有效果,可能是因为 Windows.

$ ls -la admin/langdoc.php
-rw-r--r-- 1 klor 197121 9844 Apr 25 23:04 admin/langdoc.php
$ chmod 755 admin/langdoc.php
$ ls -la admin/langdoc.php
-rw-r--r-- 1 klor 197121 9844 Apr 25 23:04 admin/langdoc.php

因为我在Windows开发,repos存储在Linux,基于chmod的权限修改不是我的方式,因为Windows不支持Linux-类似于 755 或 644 权限。

然而,

@jthill 给了我一个良好的开端,让我有了一个可行的解决方案。谢谢!

我找到了一种改进的方法,它也适用于 Windows 和 Linux,基于@jthill 的回答:

  1. 使用

    在 git 内部更改 permission/mode
    git update-index --chmod=+x file.php
    

解决方案

1.文件模式更改:模式更改 100755 => 100644

```

# 1st line just creates a file to be able to check if mode of same files are changing
git diff --raw "A" "B" | sed -n '/^:100755 100644/ s/[^\t]*.//p' > diff_mode_100755.txt
# 2nd is doing the mode change from 100755 to 100644
git diff --raw "A" "B" | sed -n '/^:100755 100644/ s/[^\t]*.//p' | xargs -d\n git update-index --chmod=+x
git commit -m "Restore original 755 file mode"

```

2。文件模式更改:模式更改 100644 => 100755

```

# 1st line just creates a file to be able to check if mode of same files are changing
git diff --raw "A" "B" | sed -n '/^:100644 100755/ s/[^\t]*.//p' > diff_mode_100644.txt
# 2nd is doing the mode change from 100644 to 100755
git diff --raw "A" "B" | sed -n '/^:100644 100755/ s/[^\t]*.//p' | xargs -d\n git update-index --chmod=-x
git commit -m "Restore original 644 file mode"

```

不清楚 "reset" 是什么意思。差异与构成差异的提交本身不同。您想要构成这些更改的所有提交(带有消息和作者身份)还是只想要最终结果?听起来您是在谈论基于 B 中的更改子集在 A 上创建一组 new 更改。

cherry-pick 提交,查看 git log B 以识别它们,然后在 A:

git cherry-pick [COMMIT_HASH]

合并分解 cherry-picks 到单个提交中,请执行:

git cherry-pick --no-commit [COMMIT_HASH1]
git cherry-pick --no-commit [COMMIT_HASH2]
...
git commit -a

分解 cherry-pick,即cherry-pick 更改 提交中:

git cherry-pick --no-commit [COMMIT_HASH]
...
git checkout some_file/we/dont/care/about
git checkout another/file/we/dont/care/about
...
git reset -p file/we/want/some/changes/from
git commit -a

checkout 放弃了给定文件的更改。 reset -p 是交互式的,就像 git add -p 相反。您已经选择了对文件的一些更改,并且正在选择要重置的更改。你留下的任何东西都是你将要提交的精简樱桃挑选的一部分。

最后,如果您只想整个文件更改(即"B's file is the right one")并且您不关心它是如何到达那里的(提交元数据),那么只需从该分支检出文件内容并提交它们:

git checkout origin/B -- path/to/file
...
git commit -a
git diff --raw A B | sed -n '/^:100755 100644/ s/[^\t]*.//p'

将列出您要从中选择的路径,对其进行编辑并通过 a-x 或 a+x 将其通过管道传输到 xargs -d\n chmod,具体取决于您是在 A 上并希望丢失 x 位还是在 B 上并想恢复它。

在 Windows 上,可执行位是无意义的,您可以直接更新索引条目,而不是 chmod a+xing 文件然后让 git 添加更新索引,git update-index --chmod=+x 设置索引位的文件,-x 清除它。

最初的问题是 Windows,但我在 Mac 上遇到了同样的问题。 @jthill 的建议很有帮助,但 sed 命令对我来说太贪心了——它会消化第一列和一半的文件路径,只留下每个文件名的最后一位。

Mac 上的 sed 似乎不能很好地解析 \t(一般来说,它似乎也不会 \s 用于白色 space) .我最终使用了一致的列宽并删除了一定数量的字符:

# Send diff to text file
git diff --raw master update_socio_eco > tmp-diff.txt

# Search for files with mode change from 644 to 755; delete initial 33 characters
# Swap order to 100755 100644 if reverting to 755
sed -nE '/:100644 100755/ s/^:.{32}//p' tmp-diff.txt >tmp-diff2.txt

# Add quotes to capture files with white space
sed -n 's/.*/"&"/p' tmp-diff2.txt >tmp-diff3.txt

# Change file mode (-x to revert to 644, +x to revert to 755)
cat tmp-diff3.txt | xargs chmod -x