record git command

Git常用回退命令总结
本文介绍了Git中常用的回退操作命令,包括如何将本地所有修改回退到之前的状态、如何暂存未提交的修改以便之后恢复、以及如何通过指定哈希值返回到特定的历史节点等。对于使用Git进行版本控制的开发者来说,这些命令非常实用。

链接有针对单个文件的回退用法:

http://blog.youkuaiyun.com/cankingapp/article/details/18312117


git checkout . #本地所有修改的。没有的提交的,都返回到原来的状态
git stash #把所有没有提交的修改暂存到stash里面。可用git stash pop回复。
git reset --hard HASH #返回到某个节点,不保留修改。

git reset --soft HASH #返回到某个节点。保留修改

网上很多,不赘述。

eclipse 配git插件是个不错的选择,当然用命令行更快捷。


mark link:

http://www.ibm.com/developerworks/cn/cloud/library/cl-contributecode-openstack/

<think>我们想要在CMake构建过程中获取当前项目中所有Git子模块的提交哈希,并将这些信息保存到一个文件中。这可以用于版本追踪,确保构建时子模块的版本是已知且一致的。思路:1.在CMake中执行命令`gitsubmodulestatus`来获取子模块的状态信息。2.解析该命令的输出,提取每个子模块的提交哈希和路径。3.将这些信息写入一个文件(例如,一个文本文件或头文件)。步骤:a.使用`execute_process`命令运行`gitsubmodulestatus`,并捕获输出。b.处理输出字符串,按行分割。c.每行的格式通常为:[状态字符][提交哈希][模块路径](描述信息,如果有)例如:+af1234bpath/to/module(v1.0)af1234bpath/to/module(v1.0)状态字符可以是:空格(表示未修改),+(表示已检出但提交与主项目记录不一致),-(未初始化)等。我们主要关心提交哈希(注意:如果有状态字符,则哈希前有一个字符,否则没有。实际上,未修改时没有前缀字符,但有空格前缀?)实际上,`gitsubmodulestatus`的输出每行都是以一个非空格字符开始(如果子模块已初始化),但未初始化的行以“-”开头。我们只处理已初始化的子模块(即忽略以“-”开头的行?),但为了完整,我们可以获取所有行的哈希(如果有)。但是注意:未初始化的子模块没有哈希值,而是显示“-”后跟40个0(或40个0的占位符)?实际上,未初始化的子模块行格式为:-<commit-hash><path>(<reason>)但是,如果未初始化,那么这里显示的提交哈希实际上是该项目记录的应该检出的提交哈希(即.gitmodules中记录的),所以我们可以取用。d.我们将提取每行中的提交哈希(固定40个字符的SHA-1?或者如果使用缩短的哈希,可能会变化?但`gitsubmodulestatus`默认输出完整的40位哈希)和模块路径。注意:每行的格式是固定的,提交哈希是40个字符(如果有状态字符,则从第二个字符开始的40个字符;没有状态字符时,从行首开始40个字符)?但是,观察:正常情况(已检出且匹配):一个空格加上40个字符的哈希?不对,实际上,已检出且匹配的是:行首没有特殊字符,而是40个字符的哈希,然后一个空格。有修改:可能前面有“+”或“-”等,但注意输出中,每行的第一个字符如果不是空格,就是状态字符(“+”、“-”或“U”等),然后是40个字符的哈希,然后是一个空格。因此,我们可以这样处理:-每行以40个字符的哈希开始,或者以状态字符后接40个字符的哈希开始?不对,状态字符后紧接着就是40个字符的哈希(中间没有空格),然后是一个空格,然后是路径。所以,如果行首是“-”、“+”或空格(注意,空格的情况可能表示未修改?但观察实际输出,未修改时没有特殊前缀字符,而是40个哈希字符开头)?实际上,输出如下(来自githelpsubmodule):-<SHA-1><path>(reason)<SHA-1><path>(describe)所以,我们分为两种情况:-如果行首是'-',则接下来的40个字符是哈希(从索引1开始到40)。-其他情况,我们假设行首的40个字符是哈希(但注意,如果没有状态字符,那么前40个字符就是哈希;如果有状态字符,那么从第2个字符开始才是哈希?实际上,状态字符只有一个字符,所以哈希从第2个字符开始,长度为40)?不对,状态字符后的40个字符是连续的。更精确地:对于每一行,我们首先去掉开头的空格(但实际输出中,行首没有空格,除了未初始化的行有“-”前缀,其他都是40个字符的哈希开头?或者有状态字符?)实际上,根据文档,`gitsubmodulestatus`输出的格式是:[<子模块状态>]<提交哈希><空格><子模块路径><可选描述>其中,子模块状态是一个字符,可以是:“”(无状态,表示与当前提交匹配)“-”(未初始化)“+”(已初始化,但当前检出提交与记录不同)“U”(存在合并冲突)所以,状态字符后紧跟40个字符的提交哈希(没有空格)。因此,我们可以统一处理:每行的第0个字符如果是状态字符(非40个字符的哈希,因为哈希都是十六进制数字),那么哈希从第1个字符开始取40个字符;否则,如果第一个字符是十六进制数字(即0-9a-f),则从第0个字符开始取40个字符。但为了简单,我们可以这样:如果行首是状态字符(即“-”、“+”或“U”),那么哈希在位置1-40;如果不是,则哈希在位置0-39。但是,状态字符只有一位,因此我们可以检查行首的字符:如果是状态字符之一,则哈希从索引1开始,否则从索引0开始。然后取40个字符。然后,剩下的部分:从哈希后面的一个空格(即状态字符+哈希之后的第一个空格,或40个哈希后的第一个空格)开始到行尾,然后我们分割出路径(空格分隔,路径是第一个空格之后的第一个单词?注意路径中可能有空格?实际上,路径中不应该有空格,因为Git子模块的路径默认不会用引号包裹)?所以,我们可以取从哈希结束位置+1(即40个字符后,或者状态字符+40个字符后的位置)开始的第一个空格之后的所有字符,直到下一个空格或行尾?但是路径后可能有描述信息(在括号里)。不过,我们只关心哈希和路径,所以我们可以这样:-定位哈希开始位置(idx_start)和长度(40),得到哈希字符串。-然后,剩余的字符串从idx_start+40+1开始(因为40个字符后,下一个字符是空格?)然后取第一个空格之后的部分,但注意:该行可能是这样的:+af1234b...40个字符...path/to/module(v1.0)af1234b...40个字符...path/to/module(v1.0)所以,在哈希后面的第一个字符是空格,然后后面就是路径(直到遇到空格或左括号?)实际上,路径是紧接着哈希后面的第一个空格后的非空字符串,直到遇到空格或行尾。但括号前有空格,所以我们可以用空格分割,然后取第一个非空部分作为路径?不对,路径可能包含空格吗?虽然不常见,但是可能的。所以,更好的方法是:从哈希结束位置+1开始,跳过空格,然后取到下一个空格或行尾?但是如果有空格在路径中,这样做会出错。因此,为了避免路径中的空格问题,我们可以利用:路径在子模块中是固定的,并且通常不会包含空格,但为了安全,我们可以选择取到行尾,然后去掉括号部分(如果有)?实际上,描述信息在括号内,且路径不会包含括号(通常),所以我们可以搜索第一个左括号'('的位置,如果有,那么路径是从哈希后的下一个空格之后开始直到左括号(但不包括左括号,且需要去掉前后的空格)。但是,如果子模块路径中有空格,那么这个解析就会出错。另一种思路:我们可以再次使用Git命令来获取每个子模块的信息,而不是解析`gitsubmodulestatus`的输出。例如,我们可以用`gitsubmoduleforeach`,但那样需要在CMake中执行多个命令,比较复杂。考虑到简单性,我们假设子模块路径中不包含空格。这样,我们可以用空格分割行,然后取第二个字段作为路径。具体步骤:1.执行命令:execute_process(COMMANDgitsubmodulestatus--recursiveWORKING_DIRECTORY${CMAKE_SOURCE_DIR}OUTPUT_VARIABLEGIT_SUBMODULE_STATUS_OUTPUTOUTPUT_STRIP_TRAILING_WHITESPACE)注意:添加`--recursive`以包括嵌套子模块。2.将输出按行分割:string(REPLACE"\n"";"GIT_SUBMODULE_STATUS_LINES"${GIT_SUBMODULE_STATUS_OUTPUT}")3.遍历每一行,提取哈希和路径:foreach(lineINLISTSGIT_SUBMODULE_STATUS_LINES)#检查行首字符:如果是状态字符(-、+、U),则哈希从第1个字符开始取40个字符;否则从第0个字符开始取40个字符。string(LENGTH"${line}"line_length)if(line_lengthLESS41)continue()#行长度不够,跳过endif()#提取状态字符(如果有)string(SUBSTRING"${line}"01first_char)if(first_charSTREQUAL"-"ORfirst_charSTREQUAL"+"ORfirst_charSTREQUAL"U")set(hash_start1)else()set(hash_start0)endif()string(SUBSTRING"${line}"${hash_start}40submodule_hash)#提取路径:从第41个字符(如果有状态字符则是42,但统一:hash_start+40的位置后开始)开始,跳过空格,直到遇到空格或行尾math(EXPRpath_start"${hash_start}+40")string(SUBSTRING"${line}"${path_start}-1rest_of_line)#去掉行首空格string(STRIP"${rest_of_line}"rest_of_line)#现在,rest_of_line应该是路径和可选的描述信息。我们取第一个空格前的部分作为路径?注意,路径中可能有空格,所以这种方法不行。#但是,我们也可以取到第一个空格之前?不行,因为可能有空格。所以,我们换一个思路:描述信息在括号内,且路径后通常有空格和括号。我们可以查找括号的位置。string(FIND"${rest_of_line}""("paren_pos)if(paren_posGREATER-1)#从开头到括号前(减去空格)string(SUBSTRING"${rest_of_line}"0${paren_pos}rest_of_line)string(STRIP"${rest_of_line}"submodule_path)else()#没有括号,那么整个剩下的字符串就是路径(但可能有空格?我们无法处理空格的情况,所以还是用整个字符串,但要去掉末尾空格?)set(submodule_path"${rest_of_line}")endif()#但是,如果路径中包含空格,我们上面的方法只能取到第一个单词。所以,我们最好不用这种方式。4.考虑另一种解析方式:使用正则表达式匹配。我们可以使用正则表达式匹配整行:^([-+U])?([0-9a-f]{40})(.+?)(?:\(.*\))?$但是,CMake的`string(REGEXMATCH)`不支持非贪婪匹配,所以我们可以分成两部分:先匹配哈希和状态,然后剩余部分去掉两端的空格,然后取第一个字段(直到空格)?同样无法处理路径中的空格。考虑到实际项目中子模块路径通常不包含空格,我们采用简单方法:用空格分割字符串,然后取第二个字段(如果有状态字符,那么哈希后是第一个字段,路径是第二个字段?没有状态字符时,哈希是第一个字段,路径是第二个字段)?但是,分割时,因为状态字符的行,哈希前面有一个状态字符,所以整个字符串分割后,第一个字段是状态字符+哈希?没有状态字符时,第一个字段是哈希,第二个字段是路径(然后后面是描述信息)?因此,我们可以:用空格分割,取第二个字段作为路径(不管是否有状态字符,因为状态字符在第一个字段的第一个字符)。这样,不管行首有没有状态字符,我们分割后的第一个字段都包含状态字符和哈希,或者只有哈希。然后,第二个字段是路径的开始?但是,描述信息在后面的字段中,所以路径可能是分割后的多个字段?因此,这种方法也不行。鉴于问题的复杂性,并且为了安全,我们只处理路径中不包含空格的情况。如果我们知道项目中的子模块路径都没有空格,那么我们可以这样:从哈希后面的第一个空格开始,取之后的部分(即剩余字符串),然后我们去掉开头的空格,然后取第一个空格之前的部分作为路径(即只取第一个单词)?但这样会忽略路径中间的空格,所以错误。另一种方法:我们使用正则表达式来匹配整个行,提取哈希和路径。正则表达式可以这样写:^([-+U])?([0-9a-f]{40})(.+?)(\([^\)]*\))?$但是,CMake的正则表达式不支持非贪婪匹配,所以我们可以:^([-+U])?([0-9a-f]{40})(.*)$然后,第三组匹配的内容是:路径和描述信息(如果有)。然后,我们再从第三组匹配的字符串中分离出路径:如果后面有括号,就去除括号部分?但是,括号可能在最后?而且描述信息可能包含空格。所以,我们可以在第三组中查找第一个空格,然后根据括号的位置来分离?或者,我们注意到描述信息总是在最后,并且用括号括起来。所以,我们可以检查第三组匹配的字符串,如果以")"结尾,并且有"(",那么最后一个"("到")"之间的部分就是描述,我们去掉这一部分以及前面的空格?但是,描述信息可能包含嵌套括号?通常不会,所以我们可以查找最后一个"("和")"?太复杂。我们重新思考:我们其实并不关心描述信息,我们只关心路径。而路径在输出中是紧跟在哈希之后,并且后面是空格和括号(如果有描述信息)。注意,描述信息不会出现在路径之前。所以,我们可以用:从第三组字符串中查找第一个空格(如果路径中有空格,那么第一个空格之后还是路径的一部分),这样是不行的。所以,最终决定:我们只取从哈希后的第一个非空格字符开始到第一个左括号(如果有)或者行尾之间的部分作为路径。如果遇到左括号,我们就截断(去掉左括号之后的内容,包括左括号),然后去掉路径末尾的空格。这样,路径中如果有空格,那么就会被截断(只保留到第一个空格)。但我们只能希望路径中没有空格。5.综上所述,我们假设路径中没有空格,那么可以这样提取:string(REPLACE""";"rest_list"${rest_of_line}")list(GETrest_list0submodule_path)6.然后,将每个子模块的哈希和路径保存到一个变量中,并写入文件。但是,考虑到实际项目中可能使用短哈希,但`gitsubmodulestatus`输出的是完整哈希(40位),我们直接使用。实现:创建一个字符串,将每个子模块的哈希和路径按行写入:格式如:path/to/module:af1234b...40位然后写入文件。示例代码:注意:CMake中字符串处理相对繁琐,我们可以编写一个自定义的脚本(用CMake内部命令)或者使用外部脚本(如Python),但为了减少依赖,我们用CMake实现。完整代码(在CMakeLists.txt中):#获取Git子模块的提交哈希execute_process(COMMANDgitsubmodulestatus--recursiveWORKING_DIRECTORY${CMAKE_SOURCE_DIR}OUTPUT_VARIABLEGIT_SUBMODULE_STATUS_OUTPUTOUTPUT_STRIP_TRAILING_WHITESPACE)#按行分割string(REPLACE"\n"";"SUBMOD_LINES"${GIT_SUBMODULE_STATUS_OUTPUT}")set(SUBMODULE_INFO_CONTENT"")foreach(lineINLISTSSUBMOD_LINES)#确保行长度足够string(LENGTH"${line}"len)if(lenLESS42)#至少40个哈希+1个空格+1个路径字符continue()endif()#检查第一个字符string(SUBSTRING"${line}"01first_char)if(first_charMATCHES"[-+U]")string(SUBSTRING"${line}"140hash)#从索引1开始取40个字符#剩余字符串从索引41开始math(EXPRrest_index"41")else()string(SUBSTRING"${line}"040hash)#没有状态字符set(rest_index40)endif()#取出剩余部分(从rest_index开始到行尾)string(SUBSTRING"${line}"${rest_index}-1rest)#移除剩余字符串前导空格string(STRIP"${rest}"rest)#在rest中查找第一个空格(如果路径没有空格,则整个字符串是路径;如果有空格,则只取第一个单词?但我们不要空格后的部分)#但我们决定:如果出现空格,则只取第一个单词(直到空格),但我们也要考虑到可能有描述信息(括号),所以先找括号string(FIND"${rest}""("paren_pos)if(paren_posGREATER-1)#截取到第一个左括号的位置,并去掉末尾空格string(SUBSTRING"${rest}"0${paren_pos}rest_path)string(STRIP"${rest_path}"rest_path)else()set(rest_path"${rest}")endif()#现在rest_path是路径部分,但可能包含空格(多个单词),我们只取第一个单词?#如果我们假设路径中没有空格,那么我们可以用空格分割并取第一个#否则,我们无法正确解析,所以我们用整个rest_path作为路径?但这样如果有描述信息,我们前面已经去掉了括号部分,剩下的路径部分可能仍然带有空格?所以,我们只取第一个单词?#这里我们按空格分割取第一个元素string(REPLACE""";"rest_list"${rest_path}")list(GETrest_list0path_only)#组合:将path_only和hash添加到内容中,格式:<path_only>:<hash>set(SUBMODULE_INFO_CONTENT"${SUBMODULE_INFO_CONTENT}${path_only}:${hash}\n")endforeach()#写入文件(在构建目录中)file(WRITE${CMAKE_BINARY_DIR}/git-submodule-info.txt${SUBMODULE_INFO_CONTENT})但是,这种方法在路径中有空格时只能取第一个单词,因此不完美。如果项目中子模块路径包含空格,建议不要使用空格。另一种改进:我们可以使用`gitsubmoduleforeach`来分别获取每个子模块的哈希,然后处理:execute_process(COMMANDgitsubmoduleforeach--recursive"gitrev-parseHEAD"WORKING_DIRECTORY${CMAKE_SOURCE_DIR}OUTPUT_VARIABLEhashes_output)但这个输出格式是:Entering'path/to/submodule'<hash>Entering...我们可以解析这种格式,但是相对麻烦,而且需要与子模块路径对应。或者,我们可以分别获取每个子模块的路径,然后对每个子模块运行`gitrev-parseHEAD`:#获取所有子模块的路径(递归)execute_process(COMMANDgitconfig--file.gitmodules--get-regexppathWORKING_DIRECTORY${CMAKE_SOURCE_DIR}OUTPUT_VARIABLEsubmodules_paths_output)#解析输出,每个子模块一行:submodule.<name>.path<path>string(REPLACE"\n"";"lines"${submodules_paths_output}")set(submodule_paths"")foreach(lineINLISTSlines)#用空格分割,取第二个元素string(REPLACE""";"items"${line}")list(LENGTHitemsn)if(nGREATER1)list(GETitems1path)list(APPENDsubmodule_paths"${path}")endif()endforeach()set(SUBMODULE_INFO_CONTENT"")foreach(pathINLISTSsubmodule_paths)execute_process(COMMANDgitrev-parseHEADWORKING_DIRECTORY${CMAKE_SOURCE_DIR}/${path}OUTPUT_VARIABLEhashOUTPUT_STRIP_TRAILING_WHITESPACE)set(SUBMODULE_INFO_CONTENT"${SUBMODULE_INFO_CONTENT}${path}:${hash}\n")endforeach()file(WRITE${CMAKE_BINARY_DIR}/git-submodule-info.txt${SUBMODULE_INFO_CONTENT})这个方法更准确,不受路径中空格影响,并且可以获取到每个子模块的当前HEAD提交。但是,这样需要执行多次`git`命令(每个子模块一次),可能会慢一点,但通常子模块数量不多。因此,我们选择这种方法。步骤:a.获取所有子模块的路径:使用`gitconfig--file.gitmodules--get-regexppath`命令。b.解析每一行,提取路径(每行第二部分)。c.对每个路径,进入该子模块的目录,运行`gitrev-parseHEAD`获取当前提交的完整哈希。d.写入文件。注意:如果子模块未初始化,则运行`gitrev-parseHEAD`会报错?所以我们需要确保在配置前子模块已经初始化?或者我们可以在配置CMake之前先初始化子模块?我们可以用`gitsubmoduleupdate--init--recursive`,但这样可能会改变用户的代码状态(除非用户已经初始化了子模块)。因此,我们假设在运行CMake时,子模块已经被初始化(因为如果未初始化,用户通常需要先运行`gitsubmoduleupdate--init`)。改进:我们可以在CMakeLists.txt中添加一个选项,如果未初始化,则初始化。但这样可能会改变用户的代码状态,所以需要谨慎。为了安全,我们只对已经初始化的子模块进行哈希获取。如果某个子模块未初始化,则跳过或者报错?在第二个方法中,如果子模块未初始化,则在进入该子模块路径执行命令时会失败。所以,我们需要确保子模块已经初始化。因此,我们可以在CMakeLists.txt的开头检查子模块,并在必要时提醒用户初始化。由于我们的主要目标只是获取子模块哈希,所以第二个方法更可靠且不受输出格式影响。我们选择第二个方法。完整代码(在CMakeLists.txt中):#获取所有子模块的路径execute_process(COMMANDgitconfig--file.gitmodules--get-regexppathWORKING_DIRECTORY${CMAKE_SOURCE_DIR}OUTPUT_VARIABLESUBMODULES_PATHS_OUTPUTOUTPUT_STRIP_TRAILING_WHITESPACEERROR_QUIET#忽略错误)if(NOTSUBMODULES_PATHS_OUTPUT)message(STATUS"Nosubmodulesfound.")return()endif()string(REPLACE"\n"";"SUBMODULE_LINES"${SUBMODULES_PATHS_OUTPUT}")set(SUBMODULE_INFO_CONTENT"")foreach(lineINLISTSSUBMODULE_LINES)string(REGEXMATCH"submodule\\..+\\.path+(.+)"matched"${line}")if(matched)set(path${CMAKE_MATCH_1})#现在,获取这个子模块的当前提交哈希execute_process(COMMANDgitrev-parseHEADWORKING_DIRECTORY${CMAKE_SOURCE_DIR}/${path}OUTPUT_VARIABLEHASHOUTPUT_STRIP_TRAILING_WHITESPACERESULT_VARIABLERES)if(RESEQUAL"0")set(SUBMODULE_INFO_CONTENT"${SUBMODULE_INFO_CONTENT}${path}:${HASH}\n")else()message(WARNING"Failedtogethashforsubmodule'${path}'.Maybeitisnotinitialized?")endif()endif()endforeach()#写入文件file(WRITE${CMAKE_BINARY_DIR}/git-submodule-info.txt${SUBMODULE_INFO_CONTENT})注意:我们使用了正则表达式匹配来提取路径,这样可以避免分割空格的问题(因为路径可能包含空格,所以不能简单分割,但正则表达式匹配会匹配整个行,然后提取等号(或空格)后的部分?不对,命令输出每行格式为:submodule.<name>.path<path>所以,正则表达式:`"submodule\\..+\\.path+(.+)"`匹配行首的固定字符串,然后一个或多个空格,然后捕获剩下的部分作为路径(即使包含空格也没问题)。但是,如果.gitmodules文件中一行有多个键值对?不会,这个命令的输出是每行一个键值对。因此,这个方法可以正确处理路径中的空格。结论:第二种方法更健壮,我们使用第二种方法。注意:`gitrev-parseHEAD`要求该子模块的.git目录存在,即已经初始化过。所以,如果用户没有初始化子模块,我们需要提醒用户运行`gitsubmoduleupdate--init`,或者我们自动执行初始化?我们可以自动初始化,但这样可能会改变用户的代码状态,所以最好由用户显式操作。因此,如果某个子模块获取哈希失败(比如返回非0),我们就打印警告,并且不在文件中记录该子模块。最后,将这个代码段放在CMakeLists.txt中的一个if语句中,例如:if(EXISTS${CMAKE_SOURCE_DIR}/.git)#执行上面的代码else()message(STATUS"Notagitrepository,skipsubmoduleinfo.")endif()或者,当用户需要时(比如通过一个选项)才执行。这样,我们就实现了在CMake中收集子模块提交哈希并保存到文件。</think> ### CMake 使用 `git submodule status` 获取提交哈希并保存到文件的最佳实践 在 CMake 中自动收集所有 Git 子模块的提交哈希并保存到文件,可以通过以下步骤实现: #### 1. 创建自定义函数收集子模块信息 ```cmake # 定义函数:收集所有子模块的哈希值 function(get_git_submodule_hashes output_file) # 获取所有子模块的路径 execute_process( COMMAND git config --file .gitmodules --get-regexp path WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE submodule_paths OUTPUT_STRIP_TRAILING_WHITESPACE ) # 检查是否有子模块 if(NOT submodule_paths) message(STATUS "No submodules found in project") return() endif() # 解析路径并获取哈希值 string(REPLACE "\n" ";" lines "${submodule_paths}") set(all_hashes) foreach(line IN LISTS lines) # 使用正则表达式提取路径 (处理路径中的空格) if(line MATCHES "submodule\\..+\\.path += +(.+)") set(submodule_path "${CMAKE_MATCH_1}") # 获取当前子模块的提交哈希 execute_process( COMMAND git rev-parse HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/${submodule_path} OUTPUT_VARIABLE commit_hash OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET ) if(commit_hash) list(APPEND all_hashes "${submodule_path}:${commit_hash}") endif() endif() endforeach() # 写入文件 string(REPLACE ";" "\n" hashes_content "${all_hashes}") file(WRITE ${output_file} "${hashes_content}") endfunction() ``` #### 2. 在配置阶段调用函数 ```cmake # 仅在 Git 仓库中执行 if(EXISTS ${CMAKE_SOURCE_DIR}/.git) # 创建输出文件路径 set(GIT_SUBMODULE_INFO_FILE "${CMAKE_BINARY_DIR}/git_submodules.txt") # 调用自定义函数 get_git_submodule_hashes(${GIT_SUBMODULE_INFO_FILE}) # 显示结果路径 message(STATUS "Git submodule hashes saved to: ${GIT_SUBMODULE_INFO_FILE}") endif() ``` #### 3. 生成的文件格式示例 ``` path/to/submodule1:a0b1c2d3e4f5a0b1c2d3e4f5a0b1c2d3e4f5a0b1 another/submodule2:f5e4d3c2b1a0f5e4d3c2b1a0f5e4d3c2b1a0f5e4 ``` #### 关键实现细节: 1. **路径处理**: - 使用正则表达式 `submodule\\..+\\.path += +(.+)` 处理路径中的空格 -
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值