主頁 > 軟體工程 > 如何將本地存盤庫中的分支合并到另一個本地存盤庫中的分支

如何將本地存盤庫中的分支合并到另一個本地存盤庫中的分支

2021-11-06 01:51:54 軟體工程

假設我有 2 個本地存盤庫。

Local Repository A //Cloned from production remote repository.

Local Repository B //Cloned from development remote repository.

從本地存盤庫 A,我創建了自己的功能分支,名為

FeatureA //In Local Repository A

從本地存盤庫 A 完成 FeatureA 后,我想將此 FeatureA 分支合并到一個名為的分支中

Developer //In Local Repository B 

請注意,FeatureA 和 Developer 兩個分支如何位于不同的本地存盤庫中。

如何將 FeatureA 分支合并到 Developer 分支?

uj5u.com熱心網友回復:

Git 實際上并不合并分支事實上,就像 Git 中的大多數事情一樣,分支在這里根本不重要:只有提交才重要。Git 合并提交

這對您來說意味著只有在所有提交都相關時才能獲得正確的結果(他們可能是,但我們看不到。 可以找到。)

關于提交有一些重要的事情需要了解(這不是一個完整的串列,但在這里對于合并很重要):

  • 它們是通過哈希 ID 找到的。
  • 散列 ID 很大、很丑,而且看起來很隨機(實際上不是隨機的,但非常不可預測,并且人類無法使用)。
  • 提交通過哈希 ID 參考其他較早的提交。這對于提交本身來說很好,畢竟它們是由計算機程式(或一系列計算機程式:我們稱之為程式git讀取的,但對于那些被認為負責這些程式和計算機的不幸的人類來說并沒有多大好處。

由于這些特殊的要點,Git 對人類做出了很大的讓步:它允許我們使用分支名稱來查找提交。不僅如此,它還有一個專為人類設計的特殊功能。什么時候我們:

  1. 首先指示 Git “在”某個特定分支,然后
  2. 直接 Git 進行新的提交,

Git 將更新我們“打開”的分支名稱,以便該名稱現在指的是新的提交,而不是指剛才它所指的任何特定提交。

對于普通的單親提交,我們可以把這種情況畫成這樣。我們首先將真實提交所具有的真實哈希 ID 替換為我們選擇以與我們虛弱的人類大腦一起作業的虛假單字母偽 ID 然后我們用一個箭頭來繪制每個提交,向后指向一個較早的提交。這將最新的提交放在右側:

... <-F <-G <-H

所以這里H代表最新提交的哈希ID commit的內部表示中某個地方H,Git 保存了早期 commit 的真實哈希 ID G我們將其繪制為從 的表示中出來的箭頭H,指向我們的 表示G

當然,G它本身也是一個提交,所以它也有一個存盤的先前提交的哈希 ID:G指向F. F同樣指向一些較早的提交,依此類推。這將永遠重復,或者更確切地說,直到我們回到有史以來的第一次提交:A在這個公式中提交(因此,我們的存盤庫只有微不足道的 8 次提交。)

出于 StackOverflow 的目的,由于懶惰和/或字體問題,我傾向于停止將提交到提交箭頭繪制箭頭,而是這樣做:

A--B--...--G--H

但實際上,從提交到提交的每個連接都只有一種方式:從較晚的提交,例如H,到較早的提交這是因為提交一旦完成,就完全是 100% 只讀的。沒有哪一個位提交都不能更改。1

當我們為這些圖紙添加分支名稱時,它們的作業方式變得更加清晰。假設我們有兩個名字,mainanddevelop和 * 兩個名字都指向 commit H,像這樣:

...--G--H   <-- main, develop

This means all commits up through and including H are on both branches. We must now pick one branch to be "on", using git checkout or git switch:3

git switch main

To remember which branch we're using, we add the special name HEAD, written in all uppercase like this, attached to just one of these branch names:

...--G--H   <-- main (HEAD), develop

This indicates that we are using commit H via the name main.

The checkout or switch command works by (very roughly):

  • removing from the work area—which Git calls the working tree—all the files that came out of some other commit, if / as needed;
  • filling in this work area with all the files from the commit we've just switched to.

We'll see this in action in a moment, but for now, let's switch to develop, or even create a new branch name feature.


1This read-only property is required to make the hashing scheme work. The hash ID of a commit is simply a cryptographic checksum of all the bits stored in that commit. If you take a commit out of a Git database, turning it into ordinary data, then modify that data in some way and put it back into the Git database, what you get is a new and different commit with a new and different hash ID. The old commit remains, unchanged, under the old ID.

Git verifies, at object-extraction time, that all the bits that come out of the database still checksum to the original value. If they don't, Git declares the database corrupt, and ceases to function. Since file contents are also stored using this same hashing trick, that's how we can be sure that none of our files are ever damaged. Once they're in the repository, they're in there forever2 and can never be changed.

2Technically, it's possible to strip commits out of a repository database, but it's tricky and we won't cover it here.

3There's no difference here between these uses of checkout and switch. Certain historical mistakes with git checkout were eventually cleaned up by splitting that one command, checkout, into two separate commands, switch and restore, and it makes sense to learn the new ones as long as you are not forced to use an old version of Git that lacks the new ones. (I have been using Git for more than 15 years at this point though so I have old and sometimes not-so-good habits here. If I use git checkout, it's by habit, or because someone gave me a Git 1.7 version to update, perhaps.)


Making new commits on a branch

If we now switch to existing branch develop, we get:

...--G--H   <-- main, develop (HEAD)

To do this, Git would need to remove all the files that came out of commit H, and instead, put in all the files from commit H. This kind of remove-and-replace-with-sameness is obviously stupid, so Git skips this step for this particular case.4 Git doesn't remove or replace any files at all this time. So if we start making changes but forget to switch to a different branch (or create a new branch; see below) it's generally safe to do that as soon as you notice your error.

Anyway, now that we're on develop, let's make a new commit in the usual way. I will skip over a lot of important detail—in particular, I won't mention Git's index aka staging area—and will just assume that you know everything there is to know here;5 and however, we do it, we now have Git make a new commit, which we will call I.:

          I
         /
...--G--H

New commit I points backwards to existing commit H. But now the special magic trick happens: Git writes the new commit's hash ID into the current branch name, i.e., the one that has HEAD attached. So to complete our drawing—and see why I put I on a line by itself here—we draw this:

          I   <-- develop (HEAD)
         /
...--G--H   <-- main

Note how the name develop now points to the new commit. All the other branch names are untouched: only the name develop moved.

If we make a second new commit J, we get:

          I--J   <-- develop (HEAD)
         /
...--G--H   <-- main

Commits up through H are on both branches, while new commits I-J are only on develop.

If we now run git checkout main or git switch main, we get this:

          I--J   <-- develop
         /
...--G--H   <-- main (HEAD)

This time, Git really does have to remove some files—those specific to commit J—and replace them with the right files for commit H. So Git does that, and if we now examine our files, we'll see that we have the files from commit H.6

Now that we're back on commit H via the name main, let's make a new branch name. We have to pick some commit for this new name to point-to, and the usual choice is "the commit we're on now", i.e., commit H:

git switch -c feature    # or git checkout -b feature

This leaves us in this state:

          I--J   <-- develop
         /
...--G--H   <-- feature (HEAD), main

If we now make two more commits, we get:

          I--J   <-- develop
         /
...--G--H   <-- main
         \
          K--L   <-- feature (HEAD)

We now have a state in which merging makes sense.


4This skipping is achieved in a smarter way than described here, but for the "switch branches without switching commits", the effect is that the change is always allowed. In more complicated cases, you get odd effects; see Checkout another branch when there are uncommitted changes on the current branch for the gory details.

5There is a lot to know! For more details, see other answers or Git tutorials.

6This is where the complications mentioned in footnote 4 can come in. Files that we forgot to commit, or deliberately didn't commit, can be carried along in the working tree and/or in Git's index aka staging-area. But if we made sure to commit everything in I and J, we'll be in a "clean" state, as reported by git status, before and after the checkout—unless things get really complicated, but let's not go there.


Merging is about combining work

Let's draw this again but change some names, switch branches around, and drop the name main entirely (it's in the way):

          I--J   <-- br1 (HEAD)
         /
...--G--H
         \
          K--L   <-- br2

We're now using commit J via name br1. We can run:

git merge <hash-of-L>

or:

git merge br2

to have Git locate commit L and do the work of a merge. Or, if we aren't ready to merge commit L yet, but want to merge in commit K, we can run:

git merge <hash-of-K>

That is, we'd run git log br2 and see commit L, then see commit K. It has some big ugly hash ID, b789abc... or whatever, and we'd grab that with the mouse, cut-and-paste style, and produce a command like:

git merge b789abc

(abbreviated hash IDs work too, so you can retype the first 4 or 7 or 15 characters and stop, but it's way too easy to make a mistake here: I always use cut-and-paste for this).

We generally don't bother to merge with some number of commits back like this, but in some complicated cases—e.g., if we have:

          o--o--...--o   <-- br1 (HEAD)
         /
...--o--*
         \
          o--...--(thousands of commits)--...--o   <-- br2

we might want to break the merge up into smaller chunks, picking some commit somewhere along the very long line of br2 to merge in first:

          o--...--o---M   <-- br1 (HEAD)
         /           /
...--o--*           /
         \         /
          o--...--o--(hundreds of commits)--...--o   <-- br2

Having merged in just 500 commits, we took an original 1400 commits down to 900 left to merge; we can do another 500, leaving only 400 left to merge, etc.

In any case, regardless of how many commits we are merging, the merge operation works the same way. Given:

          I--J   <-- br1 (HEAD)
         /
...--G--H
         \
          K--L   <-- br2

and git merge br2, Git:

  • finds the current commit J (that's easy: Git uses HEAD);
  • finds the other commit L (that's easy: Git uses br2, which we gave it); and
  • finds the merge base commit, commit H: that's harder.

Git finds that merge base commit through an algorithm, but we can just describe at as the best common ancestor, and in this case it's simply commit H.7

Git now uses the snapshots in each commit—we haven't described this properly, but each commit holds a full snapshot of every file—to figure out "what we changed" on "our branch" br2, by diffing commit H vs commit J, and to figure out "what they changed" on "their branch" by diffing commit H vs commit L. The three commits to diff here are:

  • the merge base, on the left of both git diff commands;
  • our current or HEAD commit, on the right of the "ours" diff;
  • the commit we chose to merge, on the right of the "theirs" diff.

The output from the two diffs determines the set of changes to merge.

The merge algorithm now combines these changes, applies the combined changes to the snapshot in the merge base commit—commit H here—and thus keeps our changes while adding their changes, which is what we want.

Having successfully combined these two sets of changes and applied them to the merge base, Git now makes a new commit from the result.8 That new commit is a merge commit, which is special in exactly one way: instead of pointing back to a single parent, it points back to two parents, like this:

          I--J
         /    \
...--G--H      M   <-- br1 (HEAD)
         \    /
          K--L   <-- br2

The first parent of new merge commit M is the commit we were using when we ran git merge, i.e., commit J. The other parent is the commit we named on the command line, commit L in this case. Merge commit M has, as its snapshot of all files, the result of the combining-and-applying-to-H's-snapshot.


7As the Wikipedia article notes, there is not necessarily a single unique LCA node in a DAG. For these cases, the merge algorithm gets trickier; we won't cover those here.

8If Git fails to combine the changes, it deliberately stops in the middle of the merge, leaving us a mess to clean up. We won't cover that case here either.


What this means for you

For git merge to do its job, the commits you give it must:

  • all be in one repository; and
  • be related, in terms of having some best shared commit: H in our example above.

When you have a single repository, the first condition is trivially satisfied—all the commits are in the (single) repository—and the second is usually the case because we normally make a new branch by growing it from some starting point that's on some existing branch. That shared starting point commit is a common starting point and therefore a shared commit. If there have been merges since then, there may be some better shared commit, but otherwise this is the shared commit:

 ...--*--*--*--o--o   <-- br1 (HEAD)
             \
              o----o   <-- br2

The starred commits * are on both branches, so the rightmost one works as the merge base. Or:

 ...--*--*--*--o--o--M1--o--o   <-- br1 (HEAD)
             \      /
              *----*----o----o   <-- br2

Again, all the starred commits are on both branches. The extra parent of merge commit M1 joins br2 back into br1, so once again, the rightmost starred commit works as the merge base. Once we make merge M2 we have:

 ...--*--*--*--o--o--M1--o--o--M2   <-- br1 (HEAD)
             \      /         /
              *----*----*----*   <-- br2

Note how merging "adds" all the other branch's commits to br1.

When you have two separate repositories, though, are the commits related? Now we get into one of the complications with any distributed version control system, like Git.

When you clone a Git repository, you literally copy the commits. A git clone of some repository R makes some clone C, but C has all the commits from R.9 In Git, cloning copies the commits, but doesn't copy the branches,10 which in some sense is weird—Mercurial copies the branches too, for instance—but the important thing for your case is that the commits get copied.

Now, after the commits are copied into C, someone can make more commits in R, and/or someone else can make more commits in C. But if they both follow the same sort of standard procedure—of starting with the commits they have, and merely adding on—these commits will all "join up in the past", in exactly the same way we get with a single repository.

All you have to do, in this case, is:

  • clone either of R or C into a third Git repository, then
  • add to that repository all the commits that are in the other of these two repositories, that aren't already in your third clone.

That second step—"add commits that we don't have"—might seem like a big thing. In some ways, it is ... but we already have to do that because of cloning. That is, suppose there's some "source of truth" repository Rcentral that everyone clones. You make your clone Cyou. Alice makes clone Calice, Bob makes clone Cbob, and so on.

At some point, somebody makes new commits, and eventually—somehow—gets their commits into Rcentral. And now everybody with a clone has to get those new commits into their clones, if they want to see them and use them. So we have git fetch.

We run git fetch name. Git calls the name we use here a remote. When you clone Rcentral, your Git, in your clone C, adds a standard remote name, origin. Your Git stores the URL of Rcentral under this standard name, and from now on, you can just run:

git fetch origin

to have your Git call up the Rcentral Git. They will list out their commits (by hash ID) and their branch names (by name), and your Git will figure out if any of those commits are new to you, and if so, obtain them. Your Git will then set up remote-tracking names by taking their branch names, main and feature and whatever, and sticking origin/ in front of them: the origin part comes from the remote. These names "track"11 the branch names over on origin, so they are the remote-tracking names for origin.

You can add more Git repositories as additional remotes. That is, using:

git remote add repo-xyz <url>

you add a second remote, using the name repo-xyz, to store the given url. Now you can run:

git fetch repo-xyz

Your Git will call up the Git at the URL you just saved, ask them about their branch names and commit hash IDs, and bring over any commits they have, that you don't. Your Git will then create, in your clone C, remote-tracking names of the form repo-xyz/*. You'll have a repo-xyz/main if they have a main. If they have a develop, you'll have a repo-xyz/develop.

Each of these remote-tracking names will remember exactly one commit hash ID, just as each branch name in C, Rcentral, or this added remote remembers exactly one commit hash ID. Because git fetch reads their current state, your remote-tracking names will now remember their branch state as of the time you ran git fetch.

So, having run git fetch origin and git fetch repo-xyz, you now have:

  • all the commits you had, plus
  • all the commits origin had that you didn't, plus
  • all the commits repo-xyz had that you didn't, plus
  • remote-tracking names origin/* and repo-xyz/* to remember branch names and commit hash IDs from origin and repo-xyz.

Remote-tracking names, which locate specific commits, work just as well as branch names for locating specific commits. So you can pass a remote-tracking name to git merge. The only thing they don't work for here is that you cannot get "on" a remote-tracking name. That's because it is not a branch name, and Git will only let you attach HEAD to a branch name. If you want a branch name to point to some commit that some existing remote-tracking name locates, you can use git checkout or git switch to do this:

git switch -c update-some-abc-branch repo-xyz/abc-branch

Because you have two remotes (origin and repo-xyz), you may run into the annoyance that you can't make one name, like main, that you work with when working with both origin/main and repo-xyz/main. You may need to use some funky mismatched branch names, like I just did above. That works fine: there's no need to use the same names in each repository.12

This gives you all the information you need to:

  • create branch names in your repository C to locate specific commits while getting "on" those branches;
  • run git merge with the commits identified by your branch names and/or your remote-tracking names.

As long as you remember that what Git really cares about are the commits and their hash IDs, and that your branch names are just there to let you find your chosen commits, you'll be fine.


9It's possible to make clones that omit some commits, but we'll consider the usual case where we don't do that.

10Git uses, instead, remote-tracking names. Copying branch names would be possible but would lead to confusion. The remote-tracking name technique leads, instead, to ... confusion. I'm not sure there's that much of an improvement here. ?? But it is what it is.

11 Git 嚴重過度使用了這個動詞track然而,它又是這樣。Git 將這些東西稱為遠程跟蹤分支名稱,但它們實際上并不是分支名稱,因此我使用遠程跟蹤名稱,因為它們是名稱并且它們確實跟蹤其他(遠程)名稱。

12這就是強制每個人使用相同分支名稱的 Mercurial 方法非常有用的地方。這也是強制每個人使用相同分支名稱的 Mercurial 方法如此有害的地方。這一切都取決于您需要完成什么。

uj5u.com熱心網友回復:

我發布此答案以供將來參考。

我錯誤地認為存在兩個不同的遠程存盤庫(一個用于生產,一個用于開發)。

事實證明,這個專案只有一個遠程存盤庫。

這是我應該做的。

  1. 從遠程存盤庫,只將它克隆到我的本地機器一次。

  2. 然后在我的本地機器上簽出 Production 分支。

  3. 從我剛剛簽出的 Production 分支中創建我自己的分支。

  4. 完成該功能后,將我的分支合并到 Developer 分支。

轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/349276.html

標籤:混帐 合并 分支

上一篇:即使我洗掉它,Git分支也總是神奇地出現

下一篇:1064(42000):您的SQL語法有錯誤;

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • Git本地庫既關聯GitHub又關聯Gitee

    創建代碼倉庫 使用gitee舉例(github和gitee差不多) 1.在gitee右上角點擊+,選擇新建倉庫 ? 2.選擇填寫倉庫資訊,然后進行創建 ? 3.服務端已經準備好了,本地開始作準備 (1)Git 全域設定 git config --global user.name "成鈺" git c ......

    uj5u.com 2020-09-10 05:04:14 more
  • CODING DevOps 代碼質量實戰系列第二課,相約周三

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。**《DevOps 代碼質量實戰(PHP 版)》**為 CODING DevOps 代碼質量實戰系列的第二課,同時也是本系列的 PHP ......

    uj5u.com 2020-09-10 05:07:43 more
  • 推薦Scrum書籍

    推薦Scrum書籍 直接上干貨,推薦書籍清單如下(推薦有順序的哦) Scrum指南 Scrum精髓 Scrum敏捷軟體開發 Scrum捷徑 硝煙中的Scrum和XP : 我們如何實施Scrum 敏捷軟體開發:Scrum實戰指南 Scrum要素 大規模Scrum:大規模敏捷組織的設計 用戶故事地圖 用 ......

    uj5u.com 2020-09-10 05:07:45 more
  • CODING DevOps 代碼質量實戰系列最后一課,周四發車

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。 **《DevOps 代碼質量實戰(Java 版)》**為 CODING DevOps 代碼質量實戰系列的最后一課,同時也是本系列的 ......

    uj5u.com 2020-09-10 05:07:52 more
  • 敏捷軟體工程實踐書籍

    Scrum轉型想要做好,第一步先了解并真正落實Scrum,那么我推薦的Scrum書籍是要看懂并實踐的。第二步是團隊的工程實踐要做扎實。 下面推薦工程實踐書單: 重構:改善既有代碼的設計 決議極限編程 : 擁抱變化 代碼整潔代碼 程式員的職業素養 修改代碼的藝術 撰寫可讀代碼的藝術 測驗驅動開發 : ......

    uj5u.com 2020-09-10 05:07:55 more
  • Jenkins+svn+nginx實作windows環境自動部署vue前端專案

    前面文章介紹了Jenkins+svn+tomcat實作自動化部署,現在終于有空抽時間出來寫下Jenkins+svn+nginx實作自動部署vue前端專案。 jenkins的安裝和配置已經在前面文章進行介紹,下面介紹實作vue前端專案需要進行的哪些額外的步驟。 注意:在安裝jenkins和nginx的 ......

    uj5u.com 2020-09-10 05:08:49 more
  • CODING DevOps 微服務專案實戰系列第一課,明天等你

    CODING DevOps 微服務專案實戰系列第一課**《DevOps 微服務專案實戰:DevOps 初體驗》**將由 CODING DevOps 開發工程師 王寬老師 向大家介紹 DevOps 的基本理念,并探討為什么現代開發活動需要 DevOps,同時將以 eShopOnContainers 項 ......

    uj5u.com 2020-09-10 05:09:14 more
  • CODING DevOps 微服務專案實戰系列第二課來啦!

    近年來,工程專案的結構越來越復雜,需要接入合適的持續集成流水線形式,才能滿足更多變的需求,那么如何優雅地使用 CI 能力提升生產效率呢?CODING DevOps 微服務專案實戰系列第二課 《DevOps 微服務專案實戰:CI 進階用法》 將由 CODING DevOps 全堆疊工程師 何晨哲老師 向 ......

    uj5u.com 2020-09-10 05:09:33 more
  • CODING DevOps 微服務專案實戰系列最后一課,周四開講!

    隨著軟體工程越來越復雜化,如何在 Kubernetes 集群進行灰度發布成為了生產部署的”必修課“,而如何實作安全可控、自動化的灰度發布也成為了持續部署重點關注的問題。CODING DevOps 微服務專案實戰系列最后一課:**《DevOps 微服務專案實戰:基于 Nginx-ingress 的自動 ......

    uj5u.com 2020-09-10 05:10:00 more
  • CODING 儀表盤功能正式推出,實作作業資料可視化!

    CODING 儀表盤功能現已正式推出!該功能旨在用一張張統計卡片的形式,統計并展示使用 CODING 中所產生的資料。這意味著無需額外的設定,就可以收集歸納寶貴的作業資料并予之量化分析。這些海量的資料皆會以圖表或串列的方式躍然紙上,方便團隊成員隨時查看各專案的進度、狀態和指標,云端協作迎來真正意義上 ......

    uj5u.com 2020-09-10 05:11:01 more
最新发布
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:41:12 more
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:35:34 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:05:44 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:00:18 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:20:31 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:55 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:18:51 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:00 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:17:55 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:12:06 more