SVN: 有没有办法将文件标记为“不提交”?

使用 TortoiseSVN,我可以将一个文件移动到忽略提交变更列表中,这样当我提交整个树时,不会提交对该文件的更改。

有没有办法使用 svn 命令行工具来做类似的事情?

编辑: 谢谢关于使用 svn:ignore的建议,但是它并没有完全达到我想要的效果。

svn:ignore影响像 svn addsvn import这样的东西。它给它一个可以忽略的文件名模式列表。

我有一个已经在源代码控制之下的文件,但是我想对这个文件做一些临时的更改,这些更改我不想在稍后提交整个源代码树时提交。我正在做很多其他的改变,我可以在我的显示器上贴一张纸条,告诉我在提交树之前恢复该文件,但是如果 svn 可以自动跳过该文件就更好了。

114093 次浏览

svn:ignore是你的答案。

例如:

$ svn propset svn:ignore -F .cvsignore .
property 'svn:ignore' set on '.'
svn propset "svn:ignore" "*.xml" .

*.xml是可以忽略的文件模式; 您也可以在这里使用目录名。

我不认为存储库中有忽略文件的方法。我们经常在使用 web.config 和其他配置文件时遇到这种情况。

虽然不是完美的,但是我最常看到和使用的解决方案是拥有。默认文件和一个零任务来创建本地副本。

例如,在回购中有一个名为 web.config.default的文件,它具有默认值。然后创建一个零任务,将所有的 web.config.default文件重命名为 web.config,然后可以定制为本地值。当检索到新的工作副本或运行生成时,应调用此任务。

您还需要忽略创建的 web.config文件,这样它就不会被提交到存储库中。

查看 换尿布者,它可以提供一个选项来过滤出已更改但不想提交的文件。SVN 不会自动跳过一个文件,除非你告诉它-你告诉它这个文件不同于其他文件的方式是把它放在一个变更列表。

它确实需要您做更多的工作,而且您只能将变更列表应用于您的工作副本(显然,想象一下如果您可以将“永远不更新”属性应用于修订,可能会引起的混乱!).

Subversion 没有内置的“不提交”/“忽略提交”特性,截至2016年2月/1.9版。这个答案是一个非理想的命令行解决方案

如 OP 所述,TortoiseSVN 有一个内置的变更列表,“忽略-on-commit”,它会自动从提交中排除:

  • 一个是指你想从事的工作
  • 一个是你想忽略的事情[忽略承诺]

因为 TortoiseSVN 有先例,所以对于不想提交的文件,我在示例中使用“忽略-on-commit”。我会用“工作”来表示我所做的文件,但是你可以选择任何你想要的名字。

首先,将所有文件添加到一个名为“ work”的变更列表。这必须从工作副本的根目录运行:

svn cl work . -R

这将递归地将工作副本中的所有文件添加到名为“ work”的变更列表中。这样做有一个缺点——当新文件被添加到工作副本时,您需要专门添加新文件,否则它们将不会被包括在内。其次,如果您必须再次运行这个命令,那么您需要再次重新添加所有“忽略-on-commit”文件。不理想-你可以开始在一个文件中维护自己的“忽略”列表,就像其他人做的那样。

然后,对于要排除的文件:

svn cl ignore-on-commit path\to\file-to-ignore

因为文件只能在一个变更列表中,在你之前的“工作”添加之后运行这个添加,将会从“工作”变更列表中删除你想要忽略的文件,并把它放到“忽略提交”变更列表中。

当您准备提交您想要提交的修改后的文件时,只需在提交中添加“—— cl work”即可:

svn commit --cl work -m "message"

下面是我的机器上的一个简单示例:

D:\workspace\trunk>svn cl work . -R
Skipped '.'
Skipped 'src'
Skipped 'src\conf'
A [work] src\conf\db.properties
Skipped 'src\java'
Skipped 'src\java\com'
Skipped 'src\java\com\corp'
Skipped 'src\java\com\corp\sample'
A [work] src\java\com\corp\sample\Main.java
Skipped 'src\java\com\corp\sample\controller'
A [work] src\java\com\corp\sample\controller\Controller.java
Skipped 'src\java\com\corp\sample\model'
A [work] src\java\com\corp\sample\model\Model.java
Skipped 'src\java\com\corp\sample\view'
A [work] src\java\com\corp\sample\view\View.java
Skipped 'src\resource'
A [work] src\resource\icon.ico
Skipped 'src\test'


D:\workspace\trunk>svn cl ignore-on-commit src\conf\db.properties
D [work] src\conf\db.properties
A [ignore-on-commit] src\conf\db.properties


D:\workspace\trunk>svn status


--- Changelist 'work':
src\java\com\corp\sample\Main.java
src\java\com\corp\sample\controller\Controller.java
src\java\com\corp\sample\model\Model.java
M       src\java\com\corp\sample\view\View.java
src\resource\icon.ico


--- Changelist 'ignore-on-commit':
M       src\conf\db.properties


D:\workspace\trunk>svn commit --cl work -m "fixed refresh issue"
Sending        src\java\com\corp\sample\view\View.java
Transmitting file data .done
Committing transaction...
Committed revision 9.

另一种方法是简单地将您希望提交的每个文件添加到一个“工作”变更列表,甚至不维护忽略列表,但是这也是很多工作。实际上,唯一简单、理想的解决方案是在 SVN 中实现这一点。在 Subversion 问题跟踪程序 SVN-2858中,这是一个长期存在的问题,以防将来发生这种情况。

不允许提交冲突文件。您可以利用这一点将您的私有更改排除在存储库之外。这种方法对于少量文件效果最好。

为了获得 a-file的冲突,您的工作副本(WC)没有从存储库中获得最新的 a-file,而且您的 WC 中的 a-file的更改与存储库中的更改(您尚未更新的更改)位于同一位置。如果你不想等待上面的条件,你可以像这样为 a-file创建一个冲突:
在工作副本1(WC1)中,在 a-file的顶部添加一行文本,如 “在这里制造冲突”。使用必要的语法,这样就不会破坏存储库。从 WC1提交 a-file。在 WC2中,在 a-file的顶部添加一行不同的文本,如 “我想要冲突”。从 WC2更新,现在文件应该处于冲突状态。

我来到这个线程寻找一种方法,使一个“原子”提交只是一些文件,而不是忽略一些文件提交我走了另一条路,只提交我想要的文件:

svn ci filename1 filename2

也许能帮到别人。

相反,我会编写一个 helper bash 脚本,在所有需要的文件上运行 svn commit,而不是在所有不需要的文件上运行 svn commit。这样你就有更多的控制权。

例如,只需要一行代码,就可以提交扩展名为 .h.cpp的所有文件,您对这些文件进行了更改(并且不会引起冲突) :

svn commit -m "" `svn status | grep "^M.*[h|cpp]$" | awk '{print $2}' | tr "\\n" " "`

更改/添加 [h|cpp]部分的扩展名。如果需要,在 -m ""的引号之间添加日志消息。

伙计们,我找到解决办法了。考虑到 TortoiseSVN 可以按照我们想要的方式工作,我尝试在 Linux 下安装它——也就是说,在 Wine 上运行。居然有用!你要做的就是:

  1. 通过运行“ svn changelist‘ Ignore-on-commit’”添加您想要跳过提交的文件。
  2. 使用 TortoiseSVN 提交: “ ~/. wine/drive _ c/Program Files/TortoiseSVN/bin/TortoiseProc.exe/command: commit/path:”
  3. 默认情况下,排除的文件将为 不受约束提交,而其他修改过的文件将被检查。这与 Windows 下完全相同。好好享受吧!

(需要通过 CLI 排除文件的原因是因为没有找到用于这样做的菜单项,不确定原因。不管怎样,这个很好用!)

当我面临同样的问题时,我的谷歌搜索一直没有结果,我想我找到了一个解决办法。下面是我所做的,它似乎对我有用,但是由于我仍然使用旧版本的 SVN (< 1.5,因为它没有—— keep-local 选项) ,而且我不是这方面的专家,我不能确定它是否是一个通用的解决方案。如果对你也有用,请告诉我!

我正在处理从 SVN 得到的 Prestashop 安装,因为其他人已经开始着手处理它了。由于 DB 设置是为另一台服务器完成的,所以我在/config 文件夹中的某个文件中更改了它们。由于该文件夹已经进行了版本控制,因此在 svn: 忽略中设置该文件夹不会阻止提交对其进行的本地修改。我是这么做的:

cp config ../cfg_bkp              # copy the files out of the repo
svn rm config                     # delete files both from svn and "physically"
svn propset svn:ignore "config" . # as the files no longer exists, I can add my ignore rule and then...
mv ../cfg_bkp config              # ...bring'em back
svn revert --recursive config     # make svn forget any existing status for the files (they won't be up for deletion anymore)

现在我可以运行 svn add —— force。没有添加我的配置,即使它不匹配回购的版本(我想我将不得不再次经历这一切,如果我修改它一次,没有测试)。我可以 svn 更新以及没有我的文件被覆盖或得到任何错误。

我也一直发现自己处于这种情况: 变更列表对我来说不起作用——我想创建一个我 不要想要提交的文件的简短列表,而不是维护一个我 想要提交的文件的 m-a-s-s-i-v-e 列表!

我使用的是 linux 命令行: 因此我的解决方案是创建一个脚本/usr/bin/svnn (是的,有两个 n!)如下:

#! /bin/bash
DIR=/home/mike/dev/trunk


IGNORE_FILES="\
foo/pom.xml \
foo/src/gwt/App.gwt.xml \
foo/src/main/java/gwt/Common.gwt.xml \
foo/src/main/resources/context/datasource/local.xml \
foo/src/main/resources/context/environment/local.xml"


for i in $IGNORE_FILES; do mv $DIR/$i $DIR/"$i"_; done;


svn "$@"


for i in $IGNORE_FILES; do mv $DIR/"$i"_ $DIR/$i; done;

显然,这是根据我的情况而定制的-但是只需更改 DIR 和 IGNORE _ FILES 以适应您的开发设置。记住将脚本更改为可执行的:

sudo chmod +x /usr/bin/svnn

..然后只需使用“ svnn”而不是“ svn”来运行 subversion,而不必担心检查 IGNORE _ FILES 列表中文件的本地更改。希望这个能帮上忙!

建议的一些想法可以这样实施:

PowerShell 中的 Windows

将 all 添加到 default list.ps1

dir -Recurse | ? { -not $_.PSIsContainer } | % { svn cl default $_.FullName }

添加到忽略 list.ps1

 dir file1 ... filN  % { $_.FullName } > ignore-on-commit
cat .\ignore-on-commit | % { svn cl ignore-on-commit $_ }
svn add ignore-on-commit

现在,您可以使用别名 svn ci --changelist default,这样就不必每次都指定它了。额外的好处是,您可以将忽略-on-commit 列表(如果需要的话)存储在存储库中。

对于一些不断重新生成但很少手动更改的文件,我这样做。例如,我将修订号添加到特定占位符上的配置文件中,以便在每次提交时更改文件,但手动更改很少。

我已经厌倦了等待这个内置到 SVN 中。我使用 tortoiseSVN,但是它会弹出一个用户对话框,你无法从命令行中屏蔽它。当我运行我的构建脚本并去泡茶时,我讨厌当我回来发现它在等待用户输入10% 的时候。

这里有一个 Windows PowerShell 脚本,它只提交不在变更列表中的文件:

# get list of changed files into targets
[XML]$svnStatus = svn st -q --xml C:\SourceCode\Monad
# select the nodes that aren't in a changelist
$fileList = $svnStatus.SelectNodes('/status/target/entry[wc-status/@item != "unversioned"]') | Foreach-Object {$_.path};
# create a temp file of targets
$fileListPath =  [IO.Path]::GetTempFileName();
$fileList | out-file $fileListPath -Encoding ASCII
# do the commit
svn commit --targets $fileListPath -m "Publish $version" --keep-changelists
# remove the temp file
Remove-Item $filelistPath

更新 user88044的脚本。

这个想法是在不提交变更列表中推送文件并运行邪恶脚本。

该脚本从命令 svn status —— changelist‘ do-not-commit’中提取 do-not-commit 文件

# !/bin/bash DIR = “ $(pwd)”

IGNORE _ FILES = “ $(svn status —— changelist‘ do-not-commit’| tail-n + 3 | grep-oE’[ ^ ] + $’)”

因为 i 在 $IGNORE _ FILES 中; do mv $DIR/$i $DIR/“ $i”_; done;

Svn“ $@”;

因为 i 在 $IGNORE _ FILES 中; do mv $DIR/“ $i”_ $DIR/$i; done;

脚本放在/usr/bin/svnn (sudo chmod + x/usr/bin/svnn)中

Svnn 状态、 svnn 提交等等。

您可以直接使用 TortoiseSVN 配置“忽略-on-commit”变更列表。 不需要配置任何其他变更列表,包括所有其他文件

1)单击“ SVN Commit...”(我们不会提交,只是一种为变更列表找到图形菜单的方法) 2)在列表上右键单击要排除的文件。 3)菜单: 移动到变更列表 > 忽略-对-提交

下一次执行 SVN 提交时... ... 这些文件将在列表的末尾显示为未选中,位于“忽略即提交”类别下。

测试使用: TortoiseSVN 1.8.7,Build 25475-64 Bit,2014/05/0520:52:12,Subversion 1.8.9,-release

这个问题已经很晚了,但是我找到了解决这个问题的最棒的命令行命令。不用 bash 了。好好享受吧。

svn status | grep -v excluding | sed 's/^A */"/g; s/$/"/g' | tr '\n' ' ' | xargs svn commit -m "My Message"

好的,下面是对该命令的解释。有些内容需要根据用例进行修改。

svn status

我拿到了所有文件的清单。他们都会从那些身份角色开始(?)?,!等)。每个人都有自己的路线

grep -v excluding

我使用 grep 来过滤列表。它既可以正常使用(包含) ,也可以与-v 标志一起使用(排除)。在这种情况下,它被用来排除,一个短语“排除”是什么将被排除。

sed 's/^. */"/g; s/$/"/g'

现在我删除每行开头的状态字符和空格,然后使用 sed 引用每行。我的一些文件名中有空格,因此引用。

tr '\n' ' '

我使用 tr 将所有换行符替换为空格。

xargs svn commit -m "My Message"

最后,我使用 xargs 来执行带有消息的 commit 命令。它执行提交操作,并删除引用的文件列表作为最后一个参数。

结果就是一切最终都按照我想要的方式运行。我还是有点讨厌 Svn 强迫我跳过这些该死的圈套,但我可以接受这个。我想是吧。

不忽略目录属性更改的解决方案

我试图使用基于 changelist的解决方案,但是我在它上面有一些问题。首先,我的存储库有数千个文件,因此要提交的变更列表非常庞大,而且我的 svn status输出变得太长,需要解析才有用。最重要的是,我想提交来自合并的更改,这意味着它们包括属性更改。提交变更列表时,附加到目录的 svn 属性没有提交,因此我必须进行额外的提交:

svn ci --cl work -m "this commits files from the work changelist only"
svn up
svn ci --depth empty DIR . -m "record merge properties"

您可能必须对几个目录执行此操作(这里我记录了 DIR和当前目录 .的属性) ,基本上是在发出 svn status命令时第二列中有 M的目录。

解决方案

我使用了补丁和 svn patch。在伪代码中:

svn diff $IGNORE_FILES > MYPATCH   # get the mods to ignore
svn patch --reverse-diff MYPATCH   # remove the mods
svn ci -m "message"                # check-in files and directory properties
svn patch MYPATCH                  # re-apply the mods

像其他海报一样,我最终使用一个脚本来维护要忽略的文件列表:

#! /usr/bin/env bash


finish() {
svn patch MYPATCH               # re-apply the mods
}
trap finish EXIT


IGNORE_FILES="\
sources/platform/ecmwf-cca-intel-mpi.xml \
runtime/classic/platform/ecmwf-cca.job.tmpl \
runtime/classic/platform/ecmwf-cca-intel.xml"


svn diff $IGNORE_FILES > MYPATCH # get the mods to ignore
svn patch --reverse-diff MYPATCH # remove the mods


svn "$@"

我通常与 cirevert -R .一起使用它。

如果你在 Linux 上,下面的答案将是有用的

步骤1 在工作副本的根级别创建 .svnignore文件,并在每个新行中添加文件夹/文件(例如,下面)

\.
folder1
folder2
folder3/file2.html
folder4/file1.js

注意: 您还需要添加 \.,因为它指向根目录

提示: 要获得准确的文件夹/文件路径,运行 svn st -u,然后复制粘贴相同的路径在 .svnignore文件

步骤2 运行以下命令提交除 .svnignore文件中的文件夹/文件之外的所有内容

svn ci -m "YOUR-COMMENT-HERE" $(svn st | grep -v -w -f .svnignore | awk '{print $NF}')

命令解释

╔════════════════════╦════════════════════════════════════════════════════════════════════════════════════════════════════════╗
║ svn ci             ║ Shorthand for svn commit                                                                               ║
╠════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════════════╣
║ svn st             ║ Shorthand for svn status                                                                               ║
╠════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════════════╣
║ |                  ║ Pipe(|) is used to pass output of previous command to next command's input                             ║
╠════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════════════╣
║ grep               ║ grep is a linux command to filter                                                                      ║
╠════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════════════╣
║ grep -v            ║ Give result other than matched (Inverse)                                                               ║
╠════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════════════╣
║ grep -w            ║ Exact match(used to match literal Dot(.))                                                              ║
╠════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════════════╣
║ grep -f filename   ║ Read pattern from file                                                                                 ║
╠════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════════════╣
║ awk '{print $NF}') ║ print last column data (columns are divided with space delimiter), used to get exact folder/file names ║
╚════════════════════╩════════════════════════════════════════════════════════════════════════════════════════════════════════╝