21

I have got a web application within a git repository. Due to historic reasons the web application is not at the root of the repository, it is within a folder called website. Beside that there are some other folders, so that I have got the following structure:

myApp
+- .git
+- otherFolder1
+- otherFolder2
+- otherFolder...
+- otherFolderN
+- website

The website is run on Heroku. As Heroku demands that your web application is at the root of a git repository, until now I used a build process which copied the website folder to a completely different (external) folder with its own git repository. Then I was able to push from there to Heroku and everything was fine.

Now, since git includes the subtree command this is not necessary any longer, as I could directly push from my initial folder, but just the website sub-folder, using:

git subtree push --prefix=website heroku master

Basically, this works perfectly. I only have one problem: As the previous commits to Heroku came from a completely different git repository, the history of both doesn't match each other - so Heroku detects a non-fast-forward push, and rejects the subtree push.

So how do I deal with this?

  • Idea 1: Force push. Tried that, but doesn't work as git subtree push does not have a --force option (or anything similar).
  • Idea 2: Clear Heroku's repository and start from scratch again.

I'd love to go with idea 2, but I have no idea of how to achieve this.

My first approach was to run a git push heroku :master, but Heroku detects this and denies it.

Of course, I could destroy the app and recreate it, but then all domain assignments and add-ons are gone as well, and I'd like to avoid that.

Any other ideas?

Golo Roden
  • 140,679
  • 96
  • 298
  • 425
  • dunno if it works with subtree, but you can `git fetch heroku master` followed by `git merge -s ours heroku/master` and then trying to push the subtree again. – kev Sep 28 '12 at 17:58
  • Thanks for your hint. I did that, it merged perfectly, but when I tried to push I got the very same result :-/ – Golo Roden Sep 29 '12 at 03:45
  • Unfortunately I am new to subtree's, it look like there is a subtree specific pull, could you give that a shot from the master branch from heroku? – Schneems Oct 01 '12 at 04:57
  • I am having the same issue. Did you manage to find a solution? Did the subtree specific pull work? – stian Oct 10 '12 at 10:54
  • Unfortunately I did not find a solution. What I did is destroy the app on Heroku and re-create it, then do a subtree push. This worked, but of course it's more of a workaround than of a solution :-/ – Golo Roden Oct 11 '12 at 16:05

2 Answers2

54

You can nest git commands to execute force push.

For your case the command will be:

git push heroku `git subtree split --prefix website master`:master --force
Ivan Saskor
  • 556
  • 5
  • 4
  • 4
    @Ivan, I was having the exact same problem (not with heroku, but a subtree nightmare of my own creation) and this fixed it. I'm not sure I understand what this did, though (i.e., what is the output of subtree that you can add :master on and then push it... can you elaborate a bit about why / how this works? Thanks. – Mikeage Feb 19 '13 at 05:07
  • @Sunyatasattva if I am not wrong what it does is take the commit being pushed as a subtree to the master branch, and completely overwrites the entire branch history, i.e. everything already in it will be lost. – pilau Oct 09 '13 at 12:12
  • 3
    But how to do this on Windows? I am getting `error: unknown option 'prefix'` – pilau Oct 09 '13 at 12:16
  • @pilau That seem a very scary command to run. Yet I haven't managed to make this *subtree for deployment* kind of thing work without this; the idea is great, but I think the implementation is somewhat gimmicky. – Sunyatasattva Oct 09 '13 at 12:18
  • @Sunyatasattva But did it do the trick for you eventually? I haven't managed to run this command on Powershell in Windows :/ – pilau Oct 09 '13 at 12:20
  • @pilau It works for what I meant to do (which is what is specified in the Yeoman docs linked above). Do you have `git subtree` installed? It doesn't come with most distributions of `git` I believe. – Sunyatasattva Oct 09 '13 at 12:23
  • @Sunyatasattva yes I do. A little bit of Googling about brought me [here](http://www.damian.oquanta.info/posts/one-line-deployment-of-your-site-to-gh-pages.html). Check out the last solution at the bottom, it's much cleaner and it worked for me! – pilau Oct 09 '13 at 12:30
  • @Sunyatasattva if you're still interested, I have found a much better solution that works on both Linux and Windows. Using `grunt-shell` I incorporated it into my Grunt `build` task. It is even CI-ready. It was really easy to set up and it works like a charm! https://github.com/X1011/git-directory-deploy – pilau Oct 13 '13 at 22:07
  • @pilau Thanks a lot! I will take a look at that. I am not sure I get it while reading the explaination, but perhaps getting my hands dirty is worth a thousand documentations. I will try as soon as possible. – Sunyatasattva Oct 13 '13 at 22:38
  • @Sunyatasattva It looks intimidating to set up, bit it really isn't. Took me less than 10 minutes. Major kudos to X1011 for coming up with this. I will add my implementation as an answer. – pilau Oct 15 '13 at 06:12
  • Hmmm, I guess the X1011 solution seems to be the consensus. This nested git push --force seems like a bit of a hack to me although it did work. Probably less scary if you're not using the master branch for everything though - as in my case I'm pushing to a gh-pages branch, so less to mess up. – Jesse Sep 24 '14 at 13:57
  • 1
    can someone explain that command? Is it just deleting the master branch? what is the nested command doing? For me it just deletes the master branch which is :shrug: but it does not seem to run the "nested" command. – Stop Slandering Monica Cellio Feb 17 '16 at 03:09
  • To address the error `fatal: ambiguous argument 'master' unknown revision or path not in the working tree` that occurs when trying to do this command, try to specify the branch with `-b` prefix – Adam Reis Aug 14 '16 at 00:31
  • I resolved `fatal: ambiguous argument` by just removing the branch name within the back-ticks (first occurrence of "master") – shender Jun 01 '18 at 03:28
  • I am not understanding why some people find the suggested answer a bit hacky. My 2 cents on how the command works. `git subtree split --prefix whatever_folder master` will return the commit id for the HEAD of the newly created tree having `whatever_folder` as root of the project. Thanks to the nesting (which is a shell feature, not a git one as I initially thought) that commit id will be used within a standard `git push origin commit_id:master --force`. As far as I can tell if you are fine with push forcing to the repo you should be fine with the command. – MPall Jun 26 '20 at 14:56
1

For those coming here from Yeoman's (lacking) deployment guide, there's a much, much better and easier solution developed by X1011 and I urge you all to make your lives easier and use it!

In contrast to the already issue-prone subtree method, this script actually retains your development commit delta history on your dist/build/release branch - and, you don't even need to track the dist folder in your development branches.

The setup process might look intimidating, but trust me, it's not. It took me less than 10 minutes to set up and it just worked as promised on the first run, even on a Windows machine.

If you'd like to automate it with Grunt, it is pretty easy. That's how I did it:

  1. First download X1011's deploy.sh to your main project folder.
  2. Follow the short configuration and setup guide.
  3. Install grunt-shell with node through this command: npm install grunt-shell --save-dev (--save-dev will add grunt-shell to your project's dev dependencies, in case you didn't already know). You may also use grunt-exec, they basically do the same thing, AFAIK.
  4. In Gruntfile.js, add the following object to initConfig:

Add to initConfig object

    shell: {
        deployverbose: {
          command: 'sh deploy.sh -v',
          options: {
              stdout: true,
              stderr: true
          }
        },
        deploy: {
          command: 'sh deploy.sh',
          options: {
              stdout: true,
              stderr: true
          }
        }
    }

5 . Register a new task, or add it to your existing build task (make sure you you declare the target parameter):

Add to existing build task as grunt build:deploy

if (target && target.indexOf('deploy') > -1) {
  tasks.push('deploy');
}

Standalone task grunt deploy, also allows the --verbose flag:

grunt.registerTask('deploy', 'standalone deploy command', function () {
  if (grunt.option.flags().indexOf('--verbose') > -1) {
    grunt.task.run('shell:deployverbose');
  } else {
    grunt.task.run('shell:deploy');
  }
});
pilau
  • 6,635
  • 4
  • 56
  • 69
  • Ok, I finally got time to try this solution, and I cannot get this to work. The initial setup confuses me greatly, and what happens to me when I follow the instructions seems completely opposite to what I am trying to achieve: I end up with a disconnected branch which has every file in my working dir **but** the `dist` directory. :/ – Sunyatasattva Oct 19 '13 at 05:25
  • Do you mind opening an issue at X1011's GitHub repo? It will be much easier to take it from there. Also please lay out in detail what exactly did you do, so we can pinpoint where anything might have went wrong. – pilau Oct 19 '13 at 09:58