代码之家  ›  专栏  ›  技术社区  ›  Laurence Gonsalves

性能用户的Git

  •  82
  • Laurence Gonsalves  · 技术社区  · 14 年前

    我已经用了很多年了。我想切换到在我的个人代码中使用Git,但是我看到的所有Git教程要么假设你是一个完整的源代码控制n00b(这使得它们非常乏味),要么假设你已经习惯了SVN(我没有)。

    我知道P4,我也理解分布式源代码控制系统背后的想法(所以我不需要推销,谢谢)。我想要的是一个从p4命令到等效git命令的转换表,以及“没有p4命令就不能生存”的命令。

    由于我怀疑每个P4用户都使用P4的不同子集,下面是我在P4中经常做的一些事情,我希望能够在Git中完成这些事情,这些事情在我看过的文档中并不是很明显:

    1. 在单个客户端中创建多个挂起的变更列表。( p4 change )
    2. 编辑挂起的变更列表。(也) P4变化 )
    3. 查看我所有挂起的更改列表的列表( p4 changes -s pending )
    4. 我的客户端中所有已更改文件的列表( p4 opened )或在挂起的更改列表中( p4 describe )
    5. 查看挂起的变更列表的差异(我为此使用的包装脚本使用 p4 diff P4描述 )
    6. 对于给定的文件,请查看哪些提交的变更列表影响哪些行( p4 annotate )
    7. 对于给定的文件,请参见影响该文件的变更列表的描述列表。( p4 log )
    8. 提交挂起的更改列表( p4 submit -c )
    9. 中止挂起的更改列表( p4 revert )

    其中很多都围绕着“变更列表”展开。“变更列表”是P4术语。Git等价术语是什么?

    听起来分支可能是Git用户用来代替P4所称的变更列表的。有点混乱,因为p4也有一个分支,尽管它们似乎只是模糊相关的概念。(尽管我一直认为P4的分支概念很奇怪,但它又与经典的RCS分支概念不同。)

    总之…我不知道如何用git的分支完成P4变更列表中通常要做的事情。在P4中,我可以这样做:

    $ p4 edit a.txt
    $ p4 change a.txt
    Change 12345 created.
    

    此时,我有一个包含.txt的changlist。我可以编辑描述并继续工作而不提交变更列表。另外,如果结果显示我需要对其他一些文件进行一些更改,比如说代码的其他层中的错误修复,那么我可以在同一个客户机中进行更改:

    $ p4 edit z.txt
    $ p4 change z.txt
    Change 12346 created.
    

    现在我在同一个客户机中有两个单独的变更列表。我可以同时处理这些问题,不需要做任何事情来“在它们之间切换”。当需要提交时,我可以单独提交:

    $ p4 submit -c 12346  # this will submit the changes to z.txt
    $ p4 submit -c 12345  # this will submit the changes to a.txt
    

    我不知道如何在Git中复制它。从我的实验来看 git add 与当前分支关联。据我所知,当我 git commit 它将提交所有文件 Git添加 -不管当时我在哪个部门:

    $ git init
    Initialized empty Git repository in /home/laurence/git-playground/.git/
    $ ls
    a.txt  w.txt  z.txt
    $ git add -A .
    $ git commit
     Initial commit.
     3 files changed, 3 insertions(+), 0 deletions(-)
     create mode 100644 a.txt
     create mode 100644 w.txt
     create mode 100644 z.txt
    $ vi a.txt z.txt 
    2 files to edit
    $ git status
    # On branch master
    # Changed but not updated:
    #   (use "git add <file>..." to update what will be committed)
    #   (use "git checkout -- <file>..." to discard changes in working directory)
    #
    #   modified:   a.txt
    #   modified:   z.txt
    #
    no changes added to commit (use "git add" and/or "git commit -a")
    $ git branch aardvark
    $ git checkout aardvark
    M   a.txt
    M   z.txt
    Switched to branch 'aardvark'
    $ git add a.txt 
    $ git checkout master
    M   a.txt
    M   z.txt
    Switched to branch 'master'
    $ git branch zebra
    $ git checkout zebra
    M   a.txt
    M   z.txt
    Switched to branch 'zebra'
    $ git add z.txt 
    $ git status
    # On branch zebra
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #   modified:   a.txt
    #   modified:   z.txt
    #
    $ git checkout aardvark
    M   a.txt
    M   z.txt
    Switched to branch 'aardvark'
    $ git status
    # On branch aardvark
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #   modified:   a.txt
    #   modified:   z.txt
    

    在本例中,aardvark和zebra分支似乎包含完全相同的更改集,并且基于 git status 在其中任何一个中执行提交似乎都会有相同的效果。我做错什么了吗?

    6 回复  |  直到 6 年前
        1
  •  67
  •   Community dbr    7 年前

    我没有太多的表演,所以这可能不是一对一的翻译。然后,像Git和Mercurial这样的分布式源代码管理系统有一个不同的工作流,所以实际上没有(也不应该有)1:1的转换。不管怎样,这里是:

    • 创建多个挂起的变更列表->请改用分支。在Git中,分支既轻又快,创建时间不到一秒钟,通常合并时间不到两秒钟。不要害怕分支和经常重新平衡。

      git branch new-branch-name
      git checkout new-branch-name
      

      或者一行一行地完成:

      git checkout -b new-branch-name
      
    • 查看所有挂起变更列表的列表->因为等效于多个挂起变更列表的是多个分支,所以只需查看分支:

      git branch
      

      如果还想查看远程分支:

      git branch -a
      

      成功合并后立即删除分支被认为是一种良好的做法,这样您就不必跟踪待合并和已合并的分支。

    • 列出所有已更改的文件--对于特定分支中单个挂起的“changelist”,git具有索引或缓存的概念。要提交更改,必须首先向该索引添加文件。这允许您手动选择表示单个更改的文件组或忽略不相关的文件。要查看添加哪些文件或不添加到此索引的状态,只需执行以下操作:

      git status
      
    • 请参阅挂起的变更列表的差异->这有两个部分。首先查看工作目录和索引之间的差异:

      git diff
      

      但是,如果您想知道现在键入的内容与上次提交的内容之间的差异,那么您实际上需要在工作目录+索引和头部之间进行差异:

      git diff HEAD
      
    • 对于给定的文件,请查看哪些提交的变更列表影响了哪些行->这很容易:

      git blame filename
      

      或者更好,如果您在窗口环境中:

      git gui blame filename
      

      Git GUI需要更长的时间来解析文件(它是用tcl编写的,而不是用c编写的),但它有许多非常好的功能,包括通过单击提交ID“时间旅行”回到过去的能力。我只希望他们实现一个功能,以“时间旅行”到未来,这样我就可以找到如何最终解决给定的错误;-)

    • 对于给定的文件,请参见影响该文件的变更列表的说明列表->也很容易:

      git log filename
      

      但是Git日志是一个比这更强大的工具。事实上,我的大部分个人脚本都是从git日志中提取的,以读取存储库。阅读手册页。

    • 提交挂起的变更列表->也很容易:

      git commit
      

    查看我对前一个问题的回答,以查看我典型的Git工作流: Learning Git. Need to know if I am on the right track

    如果您遵循我概述的工作流程,那么您会发现像gitk这样的工具更有价值,因为它允许您清楚地看到更改组。


    附加答案:

    Git非常灵活,有几种方法可以实现您所描述的功能。要记住的是,对于您正在处理的每个特性,总是要启动一个新的分支。这意味着主分支不会被触碰,所以您可以一直返回它来修复错误。在Git One中工作几乎总是从以下开始:

    git checkout -b new-feature-a
    

    现在您可以编辑文件a.txt。要同时处理另一个功能,请执行以下操作:

    git checkout master
    git checkout -b new-feature-z
    

    现在可以编辑文件z.txt。要切换回A.txt:

    git checkout new-feature-a
    

    但是等等,对new-feature-z进行了更改,Git不允许您切换分支。此时,您有两个选择。第一个是最简单的,将所有更改提交到当前分支:

    git add .
    git commit
    git checkout new-feature-a
    

    这是我的建议。但是,如果您真的还没有准备好提交代码,您可以临时存储它:

    git stash
    

    现在,您可以切换到branch new-feature-a。要返回您正在处理的代码,只需弹出stash:

    git checkout new-feature-z
    git stash pop
    

    全部完成后,将所有更改合并回主控形状:

    git merge --no-ff new-feature-a
    git merge --no-ff new-feature-z
    

    因为合并是如此快速和容易(容易,因为冲突是如此罕见和冲突解决,当一个发生时,不太难),我们使用Git中的分支进行所有操作。

    下面是在Git中常见使用分支的另一个例子,您在其他源代码管理工具中看不到它(除了Mercurial):

    需要不断更改配置文件以反映开发环境吗?然后使用分支:

    git checkout -b dev-config
    

    现在,在您最喜欢的编辑器中编辑配置文件,然后提交更改:

    git add .
    git commit
    

    现在,每个新分支都可以从dev config分支而不是master启动:

    git checkout dev-config
    git checkout -b new-feature-branch
    

    完成后,使用Interactive Rebase从新功能分支中删除dev config中的编辑:

    git rebase -i master
    

    删除不需要的提交,然后保存。现在您有了一个没有自定义配置编辑的干净分支。合并回主控形状的时间:

    git checkout master
    git merge --no-ff new-feature-branch
    # because master have changed, it's a good idea to rebase dev-config:
    git checkout dev-config
    git rebase master
    

    应该注意的是,删除编辑时 git rebase -i 即使所有更改都发生在同一个文件中,也可以工作。Git记住更改,而不是文件内容*。

    *注:事实上,技术上并不完全正确,但作为一个用户,这就是它的感觉


    更多附加答案:

    因此,从您的注释来看,您似乎希望同时存在两个分支,以便可以测试组合代码的工作方式。好吧,这是一个很好的方法来说明分支的力量和灵活性。

    首先,您的工作流中廉价的分支和可修改的历史的含义。当我使用cvs和svn时,我总是有点不愿意承诺。这是因为提交不稳定的代码将不可避免地影响到其他人的工作代码。但我失去了对吉特的恐惧。这是因为在Git中,在我将更改合并到master之前,其他人不会得到我的更改。所以现在我发现自己每写5行就提交一次代码。你不需要完美的远见来承诺。你只需要改变你的心态:提交到分支==add到变更集,合并到master==commit变更集。

    所以,回到例子。我会这样做的。假设你有一个分支 new-feature-z 你想用 new-feature-a . 我将创建一个新的分支来测试它:

    # assume we are currently in branch new-feature-z
    # branch off this branch for testing
    git checkout -b feature-z-and-feature-a
    # now temporarily merge new-feature-a
    git merge --no-ff new-feature-a
    

    现在你可以测试了。如果您需要修改一些东西使Feature-Z与Feature-A一起工作,那么就这样做。如果是这样,您可以将更改合并回相关分支。使用 Git ReBase-Ⅰ 从合并中删除不相关的更改。

    或者,也可以使用git-rebase临时更改new-feature-z的基础以指向new-feature-a:

    # assume we are currently in branch new-feature-z
    git rebase new-feature-a
    

    现在,分支历史记录被修改,这样new-feature-z将基于new-feature-a而不是master。现在你可以测试了。此分支中提交的任何更改都将属于分支new-feature-z。如果需要修改new-feature-a,只需切换回该分支并重新设置基片即可获得新更改:

    git checkout new-feature-a
    # edit code, add, commit etc..
    git checkout new-feature-z
    git rebase new-feature-a
    # now new-feature-z will contain new changes from new-feature-a
    

    完成后,只需重新定位到主控形状,即可从新功能A中删除更改:

    # assume we are currently in branch new-feature-z
    git rebase master
    

    不要害怕建立新的分支机构。不要害怕开一家废弃的分店。不要害怕扔掉树枝。由于merge==submit和commit==add to changeset,所以不要害怕经常提交。记住,提交是开发人员的最终撤消工具。

    哦,还有一件事,在Git中,删除的分支仍然存在于您的存储库中。所以,如果你不小心删除了一些你后来才意识到有用的东西,你可以通过搜索历史来找回它。所以不要害怕扔掉树枝。

        2
  •  1
  •   Jakob Borg    14 年前

    我没有足够的P4经验来制作一个实际的备忘单,但至少有一些相似之处可以追溯。P4“变更集”是git“提交”。

    对本地工作空间的更改将添加到“索引”中 git add ,索引稍后将与 git commit . 因此,无论出于何种目的,索引都是您的待定变更列表。

    你看变化 git diff git status 在哪里 差异比较 通常显示工作区和索引之间的更改,但是 git diff --cached 显示索引和存储库(=挂起的变更列表)之间的更改。

    关于更深入的信息,我建议 http://progit.org/book/ . 因为您一般都知道版本控制,所以您可能会跳过很多版本控制并提取特定于git的信息…

        3
  •  1
  •   Elias Bachaalany    12 年前

    我和你一样,也因为缺乏“变更列表”的概念,这与Git分支完全不同。

    我将编写一个小脚本,用该变更列表中的文件列表创建一个变更列表文件。

    另一个只需简单地调用git commit-a@change_list_contents.txt然后调用“git commit”就可以提交某个变更列表的命令

    希望能有所帮助, 埃利亚斯

        4
  •  1
  •   Russell Gallop    11 年前

    在Git中有一个更轻的替代方案,它可以构成您工作流程的一部分;使用Git临时区域。

    我通常只做一些更改,然后提交为几个提交(例如,添加调试语句、重构,实际上修复了一个bug)。与其设置性能更改列表,然后进行更改,然后提交,不如先进行更改,然后选择如何提交(可以选择使用git临时区域)。

    您可以使用以下命令行提交特定文件:

    git commit a.txt
    git commit z.txt
    

    或者先显式暂存文件:

    git add a.txt
    git commit
    git add z.txt
    git commit
    

    GitGUI允许您从文件中选择行或块,以在临时区域中构建提交。如果在一个文件中有要在不同提交中进行的更改,那么这非常有用。从吉特搬到了Perfoce,这是我真正怀念的一件事。

    在这个工作流程中有一个小的警告需要牢记。如果您对一个文件进行了更改A和B,测试该文件,然后提交A,那么您还没有测试该提交(独立于B)。

        5
  •  0
  •   Toby Allen    14 年前

    这并没有具体回答您的问题,但我不知道您是否知道2个用户、5个工作区版本的Performance可以从 perforce website .

    如果你愿意的话,你可以在家里用这种方式进行你的个人项目。其中一个烦恼是5个工作区可能有点限制,但它的性能相当令人难以置信,可用于家庭使用。

        6
  •  0
  •   dgnuff    6 年前

    在相当广泛地使用了Perforce和Git之后,只有一种方法可以让我看到靠近使用Git的Perforce变更列表的任何地方。

    首先要理解的是,要在Git中正确地实现这一功能,使其成为一个不完整的错误,例如尝试将其推送到分支中,需要进行以下更改:Git将需要为单个分支提供多个临时区域。

    Perfoce变更列表允许在Git中没有等价的工作流。考虑以下工作流:

    Check out a branch
    Modify file A and add it to changelist 1
    Modify file B and add it to changelist 2
    

    如果您尝试使用git中的分支进行此操作,您将得到两个分支,其中一个具有对文件的更改 A ,另一个对文件进行了更改 B ,但没有可以在其中看到对两个文件所做更改的位置 同时。

    我能看到的最接近的近似值是 git add . -p 然后使用 'a' 'd' 选择或拒绝整个文件的子命令。然而,这并不完全相同,这里的区别源于两个系统的一般操作方式的根本差异。

    Git(和Subversion,这不是讨论的重点)允许在不提前通知任何人的情况下更改文件。您只需更改一个文件,然后在提交更改时让Git将其全部排序。Perfonce要求您在允许更改之前主动签出一个文件,因此更改列表必须存在。从本质上讲,性能要求您在更改索引之前将文件添加到索引中。因此,在性能上需要多个变更列表,这也是为什么Git没有等价物的原因。 它根本不需要它们。