1

I have a local branch in my computer but I would like to create a new branch with no history at all (just one commit initially) and using this new branch on the remote side. How can I do that?

For example local branch has:

commit1, commit2, commit3

But I want my new branch to have only commit0 that is the code of the last state (commit3), with no previous history. I wish then to merge stuff easily for example if I do commit4 in my local branch, I wish to have only commit0 and commit4 changes in the remote branch.

How the best way to achieve this? I want mainly "compress" the stuff in the remote branch and not necessarely erase the history in my local one, to be able to still work on the local one.

  • Sounds like you just want to squash your commits, maybe on a different branch: https://stackoverflow.com/q/5189560/184546 – TTT Apr 21 '20 at 18:41
  • What if you **clone** the repo to a new folder? Then you have the most current status without further commits... – SwissCodeMen Apr 21 '20 at 19:21

1 Answers1

2

I want my new branch to have only commit0 that is the code of the last state (commit3), with no previous history.

You can get this pretty easily:

git checkout commit3    # get index and work-tree set up
git status              # make sure you're on commit3 and things are otherwise clean

then:

git checkout --orphan new-branch
git commit

and you have this new commit0 on a new branch, with no history behind it: commit0 is a new root commit.

I wish then to merge stuff easily for example if I do commit4 in my local branch, I wish to have only commit0 and commit4 changes in the remote branch.

You cannot get this at all. You can set things up so that you have commit0 and then commit5, where commit5's snapshot matches commit4's snapshot and has commit0 as its parent. But commit4—the commit with that hash ID—has commit3 as its parent, forever. Hash IDs are universal across all Git repositories, and no part of any commit can ever be changed, including its parent linkage.

It's important to realize that the word branch, in Git, is ambiguous: see What exactly do we mean by "branch"? Sometimes branch means chain of commits, terminated by one specific commit. Sometimes it means branch name. Git repositories all have their own private branch names, so there's no reason that master in the Git repository reachable at URL $url1 has to name the same commit that master in the Git repository at $url2 names.

The histories, however, are the commits. Merge works by using the history. If two chains-of-commits don't connect, there is nothing to merge.

Git does allow you to build your own solutions: it's a tool-set, not a solution in itself. You could write your own Git commands that let you add a new snapshot to a branch name of your choice, without using any of the existing commits in your actual working branches. This might let you build the device you want:

git my-private-copy-to new-branch <commit-specifier>

would run your git-my-private-copy-to command, which would add a new commit using a tree (from argument 2) to the specified branch (argument 1). Note that in the command I'm imagining—which does not exist but would just be a small shell script—there is no merging involved.

Since the command does not exist and you must write it, if you would like merging, you can put that in the command you write—but a standard merge uses, and adds to, the history recorded in the commit graph or subgraph, and you've deliberately made sure that your main work and this new-branch subgraph are disjoint subgraphs.

torek
  • 448,244
  • 59
  • 642
  • 775
  • Thanks. No, I don't want merging after reading your answer. The command is a smart approach but I can only think in a rough copy-paste files from one branch to another i feel that isn't correct. If you can give some clues of potential useful git-[command] or answers that may help to create the command / generate that commit5 I'd be very appreciated. – ANormalUser Apr 22 '20 at 00:31
  • Cherry-picking is actually a specific form of merging: it is a method by which Git will apply the parent-to-child changes (the child being the commit you cherry-pick) to the current commit, but it does so using the merge engine, treating the parent as the merge base. The `--strategy=recursive` is the default. The `--stdin` means it will read the commit hash IDs of the (multiple) commits to cherry-pick from stdin. You might be able to use `git commit-tree` as a simpler means of getting the results you want; it really depends on exactly what you want as the final snapshot. – torek Apr 22 '20 at 01:43
  • For your `git rev-list`, you probably want `--topo-order --reverse` and a limiting range, if you do go with this method. – torek Apr 22 '20 at 01:45
  • `git rev-list --reverse localbranch | git cherry-pick -n --strategy=recursive -X ours --stdin` I think this was the clue I was looking for generating that commit5. But ideally I would do this in a less "agressive way", I was able to `cherry-pick -n` commit by commit witouth "conflicts", but if I have like 2 commits bellow the `` I'd have to cherry pick those too. – ANormalUser Apr 22 '20 at 01:47
  • Remember, each Git commit stores a full snapshot of its source. If you want to copy a snapshot, that's easy, because the commit just has one. If you want to turn a snapshot into changes, that's when `git diff` or `git cherry-pick` comes in, and then things get messier. Merging (or cherry-picking) involves combining work, which is harder but often more useful. – torek Apr 22 '20 at 01:57