@@ -296,6 +296,202 @@ fn merge_subcommand_simple() {
296296 teardown_git_repo ( repo_name) ;
297297}
298298
299+ #[ test]
300+ fn merge_subcommand_with_ahead_behind ( ) {
301+ // Test that merge command works with branches that are ahead and behind
302+ let repo_name = "merge_subcommand_with_ahead_behind" ;
303+ let repo = setup_git_repo ( repo_name) ;
304+ let path_to_repo = generate_path_to_repo ( repo_name) ;
305+
306+ {
307+ // create new file
308+ create_new_file ( & path_to_repo, "hello_world.txt" , "Hello, world!" ) ;
309+
310+ // add first commit to master
311+ first_commit_all ( & repo, "first commit" ) ;
312+ } ;
313+
314+ assert_eq ! ( & get_current_branch_name( & repo) , "master" ) ;
315+
316+ // Create and checkout new branch named feature
317+ {
318+ let branch_name = "feature" ;
319+ create_branch ( & repo, branch_name) ;
320+ checkout_branch ( & repo, branch_name) ;
321+ } ;
322+
323+ {
324+ assert_eq ! ( & get_current_branch_name( & repo) , "feature" ) ;
325+
326+ // create new file
327+ create_new_file ( & path_to_repo, "feature.txt" , "feature content" ) ;
328+
329+ // add commit to branch feature
330+ commit_all ( & repo, "Initial feature commit" ) ;
331+ } ;
332+
333+ // Run git chain setup
334+ let args: Vec < & str > = vec ! [
335+ "setup" ,
336+ "chain_name" ,
337+ "master" ,
338+ "feature" ,
339+ ] ;
340+ let output = run_test_bin_expect_ok ( & path_to_repo, args) ;
341+
342+ // Verify chain setup succeeded
343+ let setup_stdout = String :: from_utf8_lossy ( & output. stdout ) ;
344+ println ! ( "CHAIN SETUP STDOUT: {}" , setup_stdout) ;
345+ assert ! (
346+ setup_stdout. contains( "Succesfully set up chain: chain_name" ) ,
347+ "Chain setup should succeed but got: {}" ,
348+ setup_stdout
349+ ) ;
350+
351+ // Go back to master and make a change
352+ checkout_branch ( & repo, "master" ) ;
353+ create_new_file ( & path_to_repo, "master_update.txt" , "master update" ) ;
354+ commit_all ( & repo, "Update master" ) ;
355+
356+ // Make a change to feature branch
357+ checkout_branch ( & repo, "feature" ) ;
358+ create_new_file ( & path_to_repo, "feature_update.txt" , "feature update" ) ;
359+ commit_all ( & repo, "Update feature" ) ;
360+
361+ // Get current branch and status before merge
362+ let current_branch = get_current_branch_name ( & repo) ;
363+ println ! ( "=== TEST DIAGNOSTICS: PRE-MERGE STATE ===" ) ;
364+ println ! ( "Current branch: {}" , current_branch) ;
365+ println ! (
366+ "Expected to be on branch feature: {}" ,
367+ current_branch == "feature"
368+ ) ;
369+
370+ // Verify branch status
371+ let args: Vec < & str > = vec ! [ ] ;
372+ let status_output = run_test_bin_expect_ok ( & path_to_repo, args) ;
373+ let status_stdout = String :: from_utf8_lossy ( & status_output. stdout ) ;
374+
375+ println ! ( "Branch status: {}" , status_stdout) ;
376+ println ! ( "Contains '2 ahead': {}" , status_stdout. contains( "2 ahead" ) ) ;
377+ println ! ( "Contains '1 behind': {}" , status_stdout. contains( "1 behind" ) ) ;
378+ println ! ( "======" ) ;
379+
380+ // Debug breaks with captured output (uncomment for debugging)
381+ // assert!(false, "DEBUG STOP: Pre-merge state");
382+ // assert!(false, "status_stdout: {}", status_stdout);
383+
384+ // Verify the "2 ahead ⦁ 1 behind" status is shown
385+ assert ! (
386+ status_stdout. contains( "2 ahead" ) ,
387+ "Branch status should show '2 ahead' but got: {}" ,
388+ status_stdout
389+ ) ;
390+ assert ! (
391+ status_stdout. contains( "1 behind" ) ,
392+ "Branch status should show '1 behind' but got: {}" ,
393+ status_stdout
394+ ) ;
395+
396+ // Run git chain merge
397+ let args: Vec < & str > = vec ! [ "merge" ] ;
398+ let output = run_test_bin ( & path_to_repo, args) ;
399+
400+ let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
401+ let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
402+ let exit_status = output. status . success ( ) ;
403+
404+ println ! ( "=== TEST DIAGNOSTICS: MERGE COMMAND RESULT ===" ) ;
405+ println ! ( "Command success: {}" , exit_status) ;
406+ println ! ( "STDOUT: {}" , stdout) ;
407+ println ! ( "STDERR: {}" , stderr) ;
408+ println ! ( "======" ) ;
409+
410+ // Debug breaks with captured output (uncomment for debugging)
411+ // assert!(false, "DEBUG STOP: Merge command result");
412+ // assert!(false, "stdout: {}", stdout);
413+ // assert!(false, "stderr: {}", stderr);
414+ // assert!(false, "exit status: {}", exit_status);
415+
416+ // Assert merge command succeeded
417+ assert ! ( exit_status, "Merge command should succeed but failed" ) ;
418+ assert ! (
419+ stdout. contains( "Successfully merged chain chain_name" ) ,
420+ "stdout should indicate successful merge but got: {}" ,
421+ stdout
422+ ) ;
423+
424+ // Check final state
425+ let args: Vec < & str > = vec ! [ ] ;
426+ let final_output = run_test_bin_expect_ok ( & path_to_repo, args) ;
427+ let final_stdout = String :: from_utf8_lossy ( & final_output. stdout ) ;
428+
429+ println ! ( "=== TEST DIAGNOSTICS: FINAL STATE ===" ) ;
430+ println ! ( "STDOUT: {}" , final_stdout) ;
431+ println ! ( "Contains '3 ahead': {}" , final_stdout. contains( "3 ahead" ) ) ;
432+ println ! ( "Contains '1 behind': {}" , !final_stdout. contains( "1 behind" ) ) ;
433+ println ! ( "======" ) ;
434+
435+ // Debug breaks with captured output (uncomment for debugging)
436+ // assert!(false, "DEBUG STOP: Final state");
437+ // assert!(false, "final_stdout: {}", final_stdout);
438+
439+ // Verify the branch status after merge - check we're correctly ahead (3 commits) and not behind
440+ assert ! (
441+ final_stdout. contains( "3 ahead" ) ,
442+ "Branch should be 3 ahead after merge but got: {}" ,
443+ final_stdout
444+ ) ;
445+ assert ! (
446+ !final_stdout. contains( "behind" ) ,
447+ "Branch should not be behind after merge but got: {}" ,
448+ final_stdout
449+ ) ;
450+
451+ // Verify successful merge message appears in command output
452+ assert ! (
453+ stdout. contains( "Successful merges: 1" ) ,
454+ "Merge output should report 1 successful merge but got: {}" ,
455+ stdout
456+ ) ;
457+
458+ // Verify files in the feature branch
459+ let file_check = run_git_command ( & path_to_repo, vec ! [ "ls-files" ] ) ;
460+ let files = String :: from_utf8_lossy ( & file_check. stdout ) ;
461+
462+ println ! ( "=== TEST DIAGNOSTICS: FILES IN FEATURE BRANCH ===" ) ;
463+ println ! ( "Files: {}" , files) ;
464+ println ! ( "Has hello_world.txt: {}" , files. contains( "hello_world.txt" ) ) ;
465+ println ! ( "Has feature.txt: {}" , files. contains( "feature.txt" ) ) ;
466+ println ! ( "Has feature_update.txt: {}" , files. contains( "feature_update.txt" ) ) ;
467+ println ! ( "Has master_update.txt: {}" , files. contains( "master_update.txt" ) ) ;
468+ println ! ( "======" ) ;
469+
470+ // Check all expected files are present
471+ assert ! (
472+ files. contains( "hello_world.txt" ) ,
473+ "Feature branch should contain hello_world.txt but got: {}" ,
474+ files
475+ ) ;
476+ assert ! (
477+ files. contains( "feature.txt" ) ,
478+ "Feature branch should contain feature.txt but got: {}" ,
479+ files
480+ ) ;
481+ assert ! (
482+ files. contains( "feature_update.txt" ) ,
483+ "Feature branch should contain feature_update.txt but got: {}" ,
484+ files
485+ ) ;
486+ assert ! (
487+ files. contains( "master_update.txt" ) ,
488+ "Feature branch should contain master_update.txt but got: {}" ,
489+ files
490+ ) ;
491+
492+ teardown_git_repo ( repo_name) ;
493+ }
494+
299495#[ test]
300496fn merge_subcommand_conflict ( ) {
301497 // Test that merge command properly handles conflicts
0 commit comments