Checkout远程git分支,如果存在,则clone clone master进行新分支并推送

时间:2016-11-24 09:01:50

标签: ruby git shell version-control fastlane

对于详细的标题感到抱歉。

fastlane中,使用编程语言Ruby,我想拥有这个功能:

if remote_branch_exist
  git_clone_remote_branch
else
  git_clone_master
  git_branch
  git_push_branch_to_master
end

我搜索了一个执行该操作的单线程git命令,但没有成功。有可能吗?

我编写的代码完全符合我的要求。但它肯定是一个不必要的代码量。

def git_clone_sdk_repo(path_repo: nil)
  some_branch = "some_branch"
  git_url = "git@github.com:MyComp/MyRepo.git"

  if check_if_remote_branch_exists(git_url: git_url, branch_name: some_branch)
    puts "remote branch exists"

    sh "git clone -b #{some_branch} #{git_url} #{path_repo}"
  else
    puts "no remote branch"

    sh "git clone #{git_url} #{path_repo}"
    pwd = Dir.pwd
    FileUtils.cd(path_repo)
    sh "git checkout -b #{some_branch}"
    sh "git push --set-upstream origin #{some_branch}"
    FileUtils.cd(pwd)
  end
end

def check_if_remote_branch_exists(git_url: nil, branch_name: nil)
  check_if_remote_branch_exists = "git ls-remote --heads #{git_url} #{branch_name} | wc -l | grep -o -q '1'"
  system(check_if_remote_branch_exists)
end

(上面代码块中的方法sh用于调用CLI命令。我认为它是fastlane的一部分。)

运行此命令:

git clone -b <some_branch> <git_url> <path_repo>

结果:

fatal: Remote branch <some_branch> not found in upstream origin

如果遥控器中没有该名称的分支。这就是为什么我首先检查是否有一个具有这样名称的远程分支。

我错过了什么简洁的git命令?

1 个答案:

答案 0 :(得分:1)

让我用Git术语重新表达这个任务,而不是Ruby代码。

您希望:

  1. 从某个URL克隆存储库。然后,我们将在通常的#34; remote&#34;下保存该URL。名称,origin

  2. 给定一个分支名称,例如foo,检查该特定分支(以便当前提交是该分支的提示)。

    如果分支可以从远程跟踪分支派生,因为(例如)通常来自master的{​​{1}}通常是真的 - 你希望Git在本地创建这个分支,相应的远程跟踪分支设置为其上游,准备对其进行操作。因此,如果origin/master上的Git存储库中存在分支foo,以便origin存在于本地存储库中,则需要使用origin/foo创建本地分支foo作为它的上游。

    如果没有,但是 - 如果没有相应的上游名称,那么此时分支将成为新分支 - 您希望创建该新分支,使其指向{{{ 1}}将指向。在这种情况下,您还希望立即(或尽快)请求origin/foo 上的Git也创建此分支名称,指向同一个提交,并且成功,将origin/master设置为origin作为其上游。理想情况下,此过程的最终结果是本地分支foo存在并且origin/foo作为其上游。

  3. 你观察到如果遥控器上存在fooorigin/foo会在一个干净的步骤中完成这一操作(虽然作为副作用,本地克隆将一个foo分支!)。但是,如果git clone -b foo <url> <directory> <遥控器上 不存在,那么克隆就会失败。

    不幸的是,没有一个Git命令能够做到这一切。此外,这里存在原子性问题(&#34;原子性&#34;在数据库或并行编程术语中具有其通常含义):在克隆过程中master不存在的事实步骤并不意味着在您要求上游存储库创建它时,foo将不存在。

    &#34; best&#34;所有这些的答案取决于你对这个原子性问题的关注程度(解决它通常只是将原子性问题移到后面的推送步骤,因为那时可以在服务器上删除分支foo,或者已经获得了额外的提交,或被重绕和重写,或其他)。但最终你必须使用多个Git命令。

    方法1

    使用最少网络流量的序列是在没有foo的情况下克隆。在这种情况下,您的克隆将自己检查一些分支 - 通常是foo,但所选择的实际分支将取决于将在URL处的Git的-b条目中的内容存储在遥控器中。然后,您的克隆将照常保存远程网址,名称为master(或您提供的任何HEAD参数)。

    现在您可以尝试origin-o已经是当前分支(因为它位于远程的git checkout foo中),因此这是一个成功的无操作;或foo不是当前分支。如果HEAD不是当前分支,则此{h}将创建foo作为本地分支,foo设置为其上游,当且仅当foo存在时。当且仅当在您执行克隆时上的远程上存在名为origin/foo的分支时,此origin/foo才会存在(请参阅&#34;原子性&#34; )。

    如果origin/foo失败,您可以认为foo不存在。 (唯一的另一种可能性是事情发生了非常严重的错误,例如,你的磁盘空间不足或者存储设备出现故障,或者Git中存在错误:在这两种情况下所有的赌注都已关闭。)你可以在此点下你的&#34;创建git checkout指向与origin/foo相同的提交,并使用foo要求在origin/master创建它&#34;路径,并验证这一切都有效。与git push -u一样,您现在正在与任何其他创建origin的人竞争。另请注意,如果您在执行克隆时其他Git上没有git push,则您自己的存储库中可能 foo

    方法2

    您可以像现在一样使用origin/master,它会对远程执行一次完整的往返操作(目前通过URL,因为目前还没有本地克隆,因此没有名为{{1}的远程} store 该URL)以确定它具有的引用集。如果该存储库中不存在master,您可以要求Git创建它。如果你愿意的话,你可以在一个新的存储库中使用一系列本地Git操作来做一些不同的事情,但是它还没有任何内容:

    git ls-remote

    此时您可以运行origin,因为现在 是名为foo的远程。但是,根本没有本地分支机构。现在我们遇到了通常的原子性问题,并且&#34;下一步做什么&#34;再次依赖于你希望如何解决它们。但是,如果我没有使用方法1或它的一些轻微变体,这就是我接下来要做的事情:

    mkdir <directory>
    cd <directory>
    git init
    git remote add origin <url>
    

    git ls-remote origin在本地存储库中创建分支,并将其设置为当前分支。由于初始提交ID由原始提交哈希给出(由于origin包含来自# assumes $branch is set to "foo" as needed, and that # function "die" prints an error message and exits with failure git fetch origin # bring over all commits and origin/* branches if branchrev=$(git rev-parse -q --verify origin/$branch); then # origin/$branch exists, so we want to act like "git clone -b $branch" git checkout $branch || die "unable to check out $branch, cannot proceed" else # origin/$branch does not exist: ask to create it pointing to # origin/master rev=$(git rev-parse -q --verify origin/master) || die "no origin/master exists, cannot proceed" git checkout -b $branch $rev || die "failed to create $branch" git push -u origin "$branch:refs/heads/$branch" || die "failed to create $branch on origin" fi 的结果),因此它将没有上游。您可以改为使用git checkout -b,但这会将新分支的上游设置为$rev,如果git rev-parse由于某种原因(例如,网络故障)失败,则会为不警情留下陷阱。您可以使用git checkout -b $branch origin/master,但考虑到测试以确保origin/master是有效名称,我们也可以在git push -u中保存哈希ID并使用它。

    如果您愿意,可以在Ruby中重写的这个shell脚本 - 可以在常规旧git checkout --no-track -b $branch origin/master之后使用,而不是使用执行所有操作的有些模糊的origin/master序列{{对于远程$rev所指示的任何分支的初始git clone,<}>将执行

    (换句话说,在实践中,我只是运行git init; git remote add ...; git fetch - 没有棘手的git clone第一部分,然后在上面的shell脚本部分执行所有操作,但< / em> git checkout步骤,在HEAD步骤之后通常是不必要的。如果克隆需要很长时间,额外的git clone可能仍然有用,因为那样然后缩小原子性比赛,代价是在-b再次往返服务器。但是没有什么可以完全关闭比赛。)