Git的Perforce用户

我已经使用Perforce多年了。 我想切换到我的个人代码使用git,但所有我见过的git教程要么假设你是一个完整的源代码控制n00b(这使得他们令人难以置信的繁琐),或者你已经习惯了svn(我不是)。

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

由于我怀疑每个p4用户使用p4的不同子集,下面是我经常在p4中做的一些事情,我希望能够在git中做到这一点,从我看过的文档中看不出来:

  1. 在一个客户端中创build多个挂起的更改列表。 ( p4 change
  2. 编辑待处理的更改列表。 (也是p4 change
  3. 看到我所有待处理的p4 changes -s pending列表( p4 changes -s pending
  4. 我的客户端中的所有已更改文件的列表(已p4 opened )或正在等待更改列表( p4 describe
  5. 看到一个待处理的更改列表的差异(我使用这个包装脚本,它使用p4 diffp4 describe
  6. 对于给定的文件,查看哪些提交的更改列表影响了哪些行( p4 annotate
  7. 对于给定的文件,请参阅影响文件的更改列表的说明列表( p4 log
  8. 提交待处理的更改列表( p4 submit -c
  9. 中止待处理的更改列表( p4 revert

其中很多都围绕着“变更名单”。 “changelist”是p4的术语。 什么是git等效项?

这听起来像分支可能是git用户用来代替p4所谓的更改列表。 有点混乱,因为p4也有一个叫做分支的东西,尽pipe它们似乎只是模糊的相关概念。 (虽然我一直认为p4的分支概念很奇怪,但是与经典的RCS分支概念再次不同。)

无论如何…我不知道如何完成我通常使用git分支的p4更改列表。 在p4中,我可以这样做:

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

在这一点上,我有一个包含a.txt的changlist。 我可以编辑描述并继续工作而不必提交更改列表。 另外,如果事实certificate,我需要对其他一些文件进行一些修改,比如在代码的其他层中说一个错误修正,我可以在同一个客户端上做到这一点:

 $ 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 add -ed的文件,不pipe我当时在哪个分支:

 $ 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 

在这个例子中,土豚和斑马分支似乎包含完全相同的一组更改,并根据git status的输出,似乎在任何一个提交都会有相同的效果。 难道我做错了什么?

我没有用太多,所以这可能不是一个1:1的翻译。 然后,像git和mercurial这样的分布式源代码pipe理系统也有不同的工作stream程,所以实际上不存在(也不应该)是1:1的翻译。 无论如何,这里是:

  • 创build多个挂起的更改列表 – >使用分支。 在git分支是轻快的,需要不到一秒的时间来创build,通常不到两秒钟就可以合并。 不要害怕经常分枝和变质。

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

    或者在一行中完成:

     git checkout -b new-branch-name 
  • 查看所有待处理的更改列表 – >由于多个待处理的更改列表的等价物是多个分支,只需查看分支:

     git branch 

    如果你想查看远程分支,

     git branch -a 

    在合并成功后立即删除一个分支被认为是一种好的做法,所以你不必跟踪哪个分支待合并和哪个分支已经被合并。

  • 列出所有更改的文件 – >对于一个特定的分支中的一个挂起的“changelist”git有一个索引或caching的概念。 为了提交更改,您必须先将文件添加到此索引。 这使您可以手动select哪个文件组代表单个更改或忽略不相关的文件。 要查看添加哪些文件的状态,或者不查看该索引,只需执行以下操作:

     git status 
  • 查看待处理更改列表的差异 – >有两个部分。 首先看到工作目录和索引之间的差异:

     git diff 

    但是如果你想知道你现在正在input的内容和最后一次提交之间的差异,那么你实际上是要求在工作目录+ index和HEAD之间进行比较:

     git diff HEAD 
  • 对于给定的文件,查看哪些提交的更改列表影响了哪些行 – >这很简单:

     git blame filename 

    或者甚至更好,如果你在窗口的环境中:

     git gui blame filename 

    Git gui花费更长的时间来parsing文件(它是用tcl而不是C编写的),但是它有许多很好的function,包括通过点击一个提交ID来“时间旅行”回到过去的能力。 我只希望他们实现一个function,以“时间旅行”到未来,所以我可以找出一个给定的错误将如何最终被解决;-)

  • 对于给定的文件,请参阅影响文件的更改列表的描述 – >也很简单:

     git log filename 

    但是git log是一个比这更强大的工具。 事实上,我的大部分个人脚本都是通过git log来读取存储库。 阅读手册页。

  • 提交待处理的更改列表 – >也很简单:

     git commit 

查看我对前一个问题的回答,查看我的典型git工作stream程: 学习Git。 需要知道我是否在正确的轨道上

如果你按照我列出的工作stream程,那么你会发现像gitk这样的工具更有价值,因为它可以让你清楚地看到一组变化。


附加答案:

Git是非常灵活的,有几种方法来做你所描述的。 要记住的是总是为你正在工作的每个function启动一个新的分支。 这意味着主分支没有被触摸,所以你总是可以回到它来修复错误。 在git中工作应该几乎总是从以下开始:

 git checkout -b new-feature-a 

现在你可以编辑文件a.txt。 同时工作另一个function:

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

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

 git checkout new-feature-a 

但是,等一下,新functionZ的变化,Git不会让你切换分支。 在这一点上,你有两个select。 第一个是最简单的,提交当前分支的所有更改:

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

这是我的build议。 但是如果你还没有准备好提交代码,你可以暂时隐藏它:

 git stash 

现在你可以切换到分支新function了。 回到你正在处理的代码,只是popup藏匿处:

 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除外)没有看到:

需要不断改变你的configuration文件来反映你的开发环境? 然后使用分支:

 git checkout -b dev-config 

现在在你喜欢的编辑器中编辑你的configuration文件然后提交更改:

 git add . git commit 

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

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

完成之后,使用交互式重新分配function从新特性分支中删除dev-config中的编辑:

 git rebase -i master 

删除你不想保存的提交。 现在你有一个干净的分支没有自定义configuration编辑。 时间合并回到主人:

 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会记住更改,而不是文件内容*。

*注意:实际上,在技术上不是完全正确的,而是作为用户的感觉


更多附加答案:

所以,从你的评论看来,你想要有两个分支同时存在,所以你可以testing如何组合的代码工作。 那么这是说明分支机构的强大和灵活性的好方法。

首先,关于便宜的分支和可修改的历史在您的工作stream程中的含义。 当我使用CVS和SVN时,我总是有点不情愿的提交。 这是因为提交不稳定的代码将不可避免地影响到其他人的工作代码。 但是用git我失去了这种恐惧。 这是因为在git中,其他人不会得到我的更改,直到我将它们合并到master。 所以现在我发现自己每写5行代码。 你不需要完美的先见之明。 你只需要改变你的想法:commit-to-branch == add-to-changeset,merge-to-master == commit-changeset。

所以,回到例子。 这是我该怎么做的。 假设你有一个分支new-feature-z ,你想用new-feature-a来testing它。 我只是创build一个新的分支来testing它:

 # 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 

现在你可以testing。 如果您需要修改某些内容以使feature-z能够与feature-a配合使用,请执行此操作。 如果是这样,您可以将更改合并到相关的分支。 使用git rebase -i从合并中删除不相关的更改。

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

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

现在,分支历史logging被修改,以便新特征-z将基于新特征-a而不是主特征。 现在你可以testing。 在该分支中提交的任何更改将属于分支new-feature-z。 如果你需要修改新function,只需切换回来,并重新获得新的变化:

 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 

完成后,只需将其重新分配给主要从新functiona删除更改:

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

不要害怕开始一个新的分支。 不要害怕开始一次性分支。 不要害怕扔掉树枝。 而且由于合并==提交和提交== add-to-changeset不要害怕经常犯。 请记住,提交是一个开发人员的最终撤销工具。

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

我没有足够的p4经验来编写一个真正的备忘单,但是至less有一些相似之处可以回溯。 一个p4“changeset”是一个git“commit”。

使用git add将本地工作空间的更改添加到“索引”,然后使用git commit索引。 所以这个索引是你所有的意图和目的。

你看看git diffgit status ,其中git diff通常显示工作空间和索引之间的变化,但是git diff --cached显示了索引和版本库(=待处理变更列表)之间的变化。

有关更深入的信息,我build议http://progit.org/book/ 。 由于您一般知道版本控制,您可能会略读一些,并提取特定于git的信息…

我和你一样缺乏“changelist”概念,这与git分支不完全一样。

我将编写一个小脚本,它将创build一个包含该更改列表中文件列表的更改列表文件。

另一个通过简单地调用git commit -a @ change_list_contents.txt然后“git commit”来提交某个更改列表的命令

希望有所帮助,埃利亚斯

git中有一个更轻量级的select,可以构成你的工作stream程的一部分; 使用git临时区域。

我经常只做更改,然后提交几个提交(例如添加debugging语句,重构,实际上修复一个错误)。 而不是设置你的perforce更改表,然后进行更改,然后提交,你可以做出你的更改,然后select如何提交(可选地使用git临时区)。

您可以从命令行提交特定的文件:

 git commit a.txt git commit z.txt 

或者首先明确地分级文件:

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

git gui会让你从文件中select行或者区块来在暂存区build立一个提交。 如果你想在不同的提交中修改一个文件,这是非常有用的。 从git移动到perforce,这是我真的很想念的一件事情。

这个工作stream程需要谨记一点。 如果您将更改A和B更改为文件,请testing该文件,然后提交A,则您尚未testing该提交(独立于B)。

这并不是专门回答你的问题,但我不知道你是否知道一个2用户,5工作区版本的perforce是免费下载和使用perforce网站 。

如果你愿意,这样你可以在家里使用perforce进行个人项目。 唯一令人烦恼的是5个工作空间可能有点限制,但是让它们可用于家庭使用是相当不可思议的。