欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

git还原文件权限

程序员文章站 2024-03-04 09:37:53
...

1. 绪言

  • 还是啰嗦的讲一下吧~项目开发的时候,新开了一个分支,不知道为啥,将大部分文件的权限都改成了755。github上的提示如下:
    git还原文件权限
  • 自己算是git小白啦,就会cloneaddcommitpushpullmerger等基本的操作,每次看commit之后的变化,都是直接看网页上的。完全不懂使用git diff命令。
  • 奈何老板是个技术流,每次使用git diff命令查看内容变化,一大推的file mode change的提示,让他觉得很烦。这不,下达命令了,让我们给解决了,将文件改回之前的权限。
diff --git a/vendor/github.com/gogo/protobuf/AUTHORS b/vendor/github.com/gogo/protobuf/AUTHORS
old mode 100644
new mode 100755
  • 问题来了,这不是已经commit过的内容吗?会一直留在log中啊,何来去除一说?原因: 估计这就是因为我们不怎么使用git diff命令导致的吧。如果使用git diff命令,我们会发现如果恢复了原本的权限,上面的内容就会消失,不会影响我们阅读commit之间的差异!

2. 讲讲linux的文件权限

  • 使用ls - al可以查看文件的权限,我们关注第一串字符,共10个。
drwxr-xr-x   2 hadoop hadoop   4096 11月 10 13:32 模板
  • 字符的含义如下:
    ① 第一个字符代表文件(-)、目录(d),链接(l
    ② 其余字符每3个一组(rwx),读(r)、写(w)、执行(x)
    (1)第一组rwx:表示文件所有者的权限(用户权限u)是读、写和执行
    (2)第二组rw-:与文件所有者同一组的用户的权限(组权限g)是读、写但不能执行
    (3)第三组r--:不与文件所有者同组的其他用户的权限(不同组其他用户权限o)是只读,不能写和执行
    ③ 可以使用chmod设置文件权限,其中每组的rwx都可以看做二进制的1或者0。比如rwxr-xr-x表示111 101 101,所以换算成10进制就是755。chmod 755 1.txt命令便表示:为1.txt这个文件赋权限为755。
    ④ 也可以使用chmod +、-、=设置权限,最基础的是644。原本一个文件权限为644(rw-r--r--),通过chmod +x就变成rwxr-xr-x,即755.
    注意: chmod +xchmod a+x 是一样的,一般没有明确要求,可以就用chmod +x。而chmod +xchmod u+x的是不一样的,后者只为所有者设置了可执行权限。
    git还原文件权限
  • 我们这次遇到的file mode跟linux 中的又不太一样,因为他多了100。其实100表示普通文件,其他常见类型如下所示:
    0100000000000000 (040000): Directory
    1000000110100100 (100644): Regular non-executable file
    1000000110110100 (100664): Regular non-executable group-writeable file
    1000000111101101 (100755): Regular executable file
    1010000000000000 (120000): Symbolic link
    1110000000000000 (160000): Gitlink
  • 之后可以使用如下命令让git忽略文件权限的改变,可以在.git/config中查看到相关设置是否生效。
git config --add core.filemode false

参考链接:
linux下chmod +x的意思?为什么要进行chmod +x
Linux下用户组、文件权限详解
git file mode change

3. 老板给的解决方法

  • 老板直接在github中添加注释,告诉了我们解决办法。我只看得懂|之前的部分和chmod,后面的xargs-x就让我蒙圈了。后来询问了技术流的师兄,耐心给我做了解答,终于知道含义了。
find . -name *.go | xargs chmod -x
  • 师兄给的解决办法,应该是一样的效果,只是多了-executable选项,表示查找有执行权限的go文件。
find . -name `*.go` -executable | xargs chmod -x
  • find . -name *.go用于查找到我们想要恢复权限的go文件。
① 关于xargs
  • 在日常处理中,某些命令需要使用前一命名的输出作为命令参数进行输入,但是这些命令缺不支持通过管道 | 传输数据,这时候可以使用xargs命令去实现。
  • 我们先看看下面的两个命令,就多了一次xargs,怎么结果千差万别呢。一个把'--help'作为了cat需要展示的文件内容,一个把'--help',作为了cat的选项。
$ echo '--help' | cat 
--help
$ echo '--help' | xargs cat 
用法:cat [选项]... [文件]...
Concatenate FILE(s) to standard output.

如果没有指定文件,或者文件为"-",则从标准输入读取。

  -A, --show-all           equivalent to -vET
  -b, --number-nonblank    number nonempty output lines, overrides -n
  -e                       equivalent to -vE
  -E, --show-ends          display $ at end of each line
  -n, --number             number all output lines
  -s, --squeeze-blank      suppress repeated empty output lines
  -t                       与-vT 等价
  -T, --show-tabs          将跳格字符显示为^I
  -u                       (被忽略)
  -v, --show-nonprinting   使用^ 和M- 引用,除了LFD和 TAB 之外
      --help		显示此帮助信息并退出
      --version		显示版本信息并退出

示例:
  cat f - g  先输出f 的内容,然后输出标准输入的内容,最后输出g 的内容。
  cat        将标准输入的内容复制到标准输出。
  • echo '--help' | cat该命令输出的是echo的内容,也就是说将echo的内容当作cat处理的文件内容了,实际上就是echo命令的输出通过管道定向到cat的输入了。然后cat从其标准输入中读取待处理的文本内容。这等价于在test.txt文件中有一行字符 '--help'然后运行 cat test.txt的效果。
  • echo '--help' | xargs cat 等价于 cat --help。就是xargs将其接受的字符串 --help 做成cat的一个命令参数来运行cat命令 ,同样 echo 'test.c test.cpp' | xargs cat 等价于 cat test.c test.cpp 此时会将test.c和test.cpp的内容都显示出来
  • 经常将find命令查找到文件传递给xargs命令,由xargs命令将这些文件作为后续命令的参数并运行后续命令。
② 整个命名的意思
  • 通过对chmod -xxargs命令的分析,其实整个命令就是想通过find查找到所有的go文件,然后将这些go文件的权限去掉可执行权限,让其从755恢复成644。
  • 如果想让其从644恢复成755,改为chmod +x就可以了。

参考链接:
xargs命令详解,xargs与管道的区别
linux之find命令详解

3. 问题的解决

  • 在项目目录下执行find . -name *.go | xargs chmod -x命令, 就可以恢复go文件的权限。其他文件照葫芦画瓢就可以。
  • 执行完以后,通过以下命令进行提交(这是师兄告诉的)。
git  add -u # -u, --update, 更新已跟踪的文件
git  commit -m ”XXXX“
git push  -u origin test
  • 师兄还叮嘱我一定要注意为什么加上了可执行权限,不然之后还可能出现这样的问题。超级认真,不愧是技术流大佬!

4. 那么多类型的文件需要该权限,添麻烦了

  • 除了go文件,还有很多.md、.yml、.json等常见类型的文件,关键还有很多不常见类型的文件。不仅文件类型这么多,还有一些go文件人家本身是755的,由于我的操作,变成了644。。。通过find命令何时才能处理完?
  • 清华的小伙伴就用go语言做起了diff的结果解析,判断文件mode,写出了设立了脚本进行处理。真的是大佬啊!
package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
)

func main() {
	fi, err := os.Open("diff.out")
	if err != nil {
		panic(err)
	}
	defer fi.Close()

	var diff string
	var oldMode string
	br := bufio.NewReader(fi)
	for {
		line, _, err := br.ReadLine()
		if err == io.EOF {
			break
		}
		if strings.HasPrefix(string(line), "diff --git") {
			diff = strings.Replace(string(line), "diff --git ", "", 1)
			diff = strings.Split(diff, " ")[0]
			diff = strings.Replace(diff, "a/", "", 1)
		}
		if strings.HasPrefix(string(line), "old mode 100") {
			oldMode = strings.Replace(string(line), "old mode 100", "", 1)
		}
		if strings.HasPrefix(string(line), "new mode 100") {
			fmt.Println(fmt.Sprintf("chmod %s %s", oldMode, diff))
		}
	}
}
  • 运行的时候可以将输出重定向如 go run main.go > mode.sh,然后再项目目录下运行mode.sh即可使得所有的文件mode和master一致。
  • 附加链接:Git diff 常见用法