代码之家  ›  专栏  ›  技术社区  ›  kakakali

如何只提交部分文件?

  •  0
  • kakakali  · 技术社区  · 4 年前

    正如前文所述

    git - How do I commit only some files? - Stack Overflow

    我们可以使用

     git commit [--only] a b c -m "only part of files"
    

    然而,在以下示例中:

    $ mkdir t
    $ cd t
    $ git init
    Initialized empty Git repository in /mnt/c/test/git-test/t/.git/
    $ touch a b
    $ git add .
    $ git commit a -m a
    [master (root-commit) c7939f9] a
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 a
    $ git commit b -m b
    [master cf4514a] b
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 b
    $ git status
    On branch master
    nothing to commit, working tree clean
    $ ls
    a  b
    

    我试图在第二次提交中只提交文件b,但失败了。(工作树中有a、b,工作树干净。这意味着这两个文件都已提交。)

    那么,如何真正提交部分文件呢?

    甚至 git add 单个文件不起作用:

    $ mkdir t
    $ cd t
    $ git init
    Initialized empty Git repository in /mnt/c/test/git-test/t/.git/
    $ touch a b
    $ git add a
    $ git commit --only a -m "a"
    [master (root-commit) 04383c9] a
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 a
    $ git rm --cached -r .
    rm 'a'
    $ git add b
    $ git commit --only b -m "b"
    [master d518916] b
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 b
    $ git checkout -f head~
    Note: switching to 'head~'.
    
    ...
    HEAD is now at 04383c9 a
    $ ls
    a
    $ git checkout -f master
    Previous HEAD position was 04383c9 a
    Switched to branch 'master'
    $ ls
    a  b
    

    文件a仍在第二次提交中。

    背景 假设我有一个包含许多文件的文件夹,我想将文件集a提交到第一次提交中(即第一次提交只包含文件集a),将文件集B提交到第二次提交中,。。。 我为什么这样做:只是出于好奇。

    1 回复  |  直到 4 年前
        1
  •  2
  •   torek    4 年前

    添加到 Mark Adelsberger's answer 和地址 your comment here :

    我过去把commit当作快照,而不是diff内容。所以我希望commit命令只是获取索引的快照并存储它。

    这个 是正确的 。但是,当您使用 git commit --only Git实现这一点的方式很复杂。(这也没有很好的记录。)

    我通常谈论的是“索引/暂存区/缓存”。Git确实有一个特定的可分辨索引,“the”索引,尽管它实际上是每个工作树的:如果你运行 git worktree add ,您不仅会得到一个新的工作树,还会得到一个新索引(以及新的 HEAD ,以及其他特定于工作树的引用,例如 git bisect ). 但是Git能够处理额外的临时索引文件,这就是 git提交--仅限 git commit --include 做。

    让我们再次查看您的设置:

    $ mkdir t
    $ cd t
    $ git init
    Initialized empty Git repository in /mnt/c/test/git-test/t/.git/
    $ touch a b
    $ git add .
    

    此时,“the”指数( .git/index )包含两个文件。它们在这里:

    $ git ls-files --stage
    100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0       a
    100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0       b
    

    然而,现在你跑 git commit a -m a ,创建初始提交(根提交,没有父级)。此命令 git commit --only a ,或多或少由以下人员完成:

    1. 创建新的临时索引, .git/index digits ;
    2. 从当前提交初始化该索引; 1.
    3. 运行相当于 GIT_INDEX_FILE=.git/index digits add a ;
    4. 运行相当于 cp .git/index .git/index. moredigits 创建a 第二 临时指标;
    5. 运行相当于 GIT_INDEX_FILE=.git/index. moredigits add a ; 2.
    6. 以某种方式从第一个临时索引构建提交 git commit 通常从主索引构建提交; 3.
    7. 通过重命名来完成提交 第二 临时索引 .git/index ,使其成为主要指标。

    它的作用是:

    • 为包含以下内容的提交创建并使用临时索引 头部 承诺加上 --only 文件夹。在新提交失败的情况下,主索引不受干扰(尽管在您的情况下它成功了)。
    • 创建并设置第二个临时索引,以便在提交成功时使用。
    • 尝试使用第一个临时索引进行提交。

    如果提交成功,则丢弃第一个临时索引,第二个临时索引成为主索引(通过 rename 操作,使其完全原子化)。如果提交失败,两个临时索引文件都将被删除。

    这意味着在a之后 成功的 git提交--仅限 ,主索引会更新,就像您运行过一样 git add --只有 文件夹。a之后 失败 一个提交可能会因为预提交钩子而失败,或者你删除了提交消息,因为instanceall就像你从未运行过一样 git提交--仅限 完全。

    (就你而言,因为你没有修改文件 a 跑步前 git commit——只有一个 ,你无法区分其中一些案件。)

    当你继续奔跑时 git commit --only b ,重复这些步骤,但有文件 b 而不是文件 .


    1. 当前没有提交,因为您还没有创建任何提交,所以这被视为一种特殊情况:Git将其创建为空索引。

    2. 这个 git添加 由于文件名为 仍然是空的。您是否修改了名为的文件 不过,此时在您的工作树中,它将更新第二个临时索引。

    3. 由于Git未使用该文件 .git/index 为了构建这个新的提交,任何预提交钩子 假设 索引被命名 .git/index 会做错事。请注意,添加工作树后,该添加工作树的主索引也有不同的名称( .git/worktrees/<name>/index ,如果我没记错的话)。

        2
  •  1
  •   Mark Adelsberger    4 年前

    git commit [--only] path 承诺 变化 仅限于指定的文件。

    所以你从一个空的仓库开始。您暂存了两个新文件: a b 。现在你有两件事在上演(你可以用 git status ):

    • 新文件
    • 新文件 b

    你说

    git commit a -m a
    

    如果你跑了 git状态 此时,你会看到,实际上只有 已承诺; 现已承诺 b 仍作为“新文件”暂存。然后你说

    git commit b -m b
    

    仅承诺 b , 离开 与上一次提交保持不变 .

    同样,您可以确认每次提交只影响您指定的文件

    git log --name-status
    

    这将显示第一次提交只添加了 第二个只添加了 b .

    听起来你想要一个命令来创建一个提交 仅包含 指定的文件。要做到这一点,你需要承诺 变化 不仅包括您要添加的任何新文件,还包括您要删除的任何旧文件。这就是为什么你的第二次尝试失败了:你成功创建了一个只包含你想要的文件的暂存区,但后来你告诉 git 不将更改应用于除新文件之外的任何内容。如果不是

    git commit --only b -m "b"
    

    你刚才只是说

    git commit -m "b"
    

    它会做你想做的事。

        3
  •  0
  •   gardner    4 年前

    解决方案很简单:添加到您感兴趣的仅限阶段的文件中。 例如 add . 意味着将当前目录中的所有文件添加到stage中。相反 转到文件夹 a 并键入add .